Mongoose query using Javascript Object vs Javascript Map - node.js

I have a mongoose model that has a field called timeLimit which is an Object
timeLimit: {
type: Object,
// of: Date,
},
If I try to find documents in this collection using the following query
const docs = await Model.find({
'timeLimit.end': {
$gt: moment().utc(),
},
});
I get no result, despite the fact that there are valid values to be returned. However, if I change the field in the model to match a Map of Dates...
timeLimit: {
type: Map,
of: Date,
},
The query returns the valid values of this query.
My question is, why is the query invalid when using the Object mongoose type if MongoDB doesn't even have the Map type, only the Object type?

Related

Mongoose Query with Dynamic Key that also contains the "and" operator

So I'm trying to query my MongoDB database using mongoose to fetch documents that have a specific family AND a specific analysis ID at the same time. Here is an example of the document structure:
_id: ObjectId("62b2fb397fda9ba6fe24aa5c")
day: 1
family: "AUTOMOTIVE"
prediction: -233.99999999999892
analysis: ObjectId("629c86fc67cfee013c5bf147")
The problem I face in this case is that the name of the key of the family field is set dynamically and could therefore have any other name such as "product_family", "category", etc. This is why, in order to fetch documents with a dynamic key name, I have to use the where() and equals() operators like so:
// Get the key of the field that is set dyncamically.
let dynamicKey = req.body.dynamicKey;
// Perform a query using a dynamic key.
documents = await Model.find().where(dynamicKey).equals(req.body.value);
HOWEVER, my goal here is NOT to just fetch all the documents with the dynamic key, but rather to fetch the documents that have BOTH the dynamic key name AND ALSO a specific analysis Id.
Had the family field NOT been dynamic, I could have simply used a query like so:
documents = await Model.find({
$and: [{analysis: req.body.analysis_id}, {family: req.body.value}]
});
but this does not seem possible in this case since the keys inside the find() operator are mere text strings and not variables. I also tried using the following queries with no luck:
documents = await Model.find().where(dynamicKey).equals(req.body.value).where('analysis').equals(req.body.analysis_id);
documents = await Model.find().where(dynamicKey).equals(req.body.value).where('analysis').equals(req.body.analysis_id);
Can somebody please help?
As #rickhg12hs mentioned in the comments, part of the answer is to use the [] brackets to specify your dynamic key like so:
await Model.find({[dynamicKey]: req.body.value, analysis: req.body.analysis_id});
I also found out that another query that can work is this:
await Model.find({analysis:req.body.analysis_id}).where(dynamicKey).equals(req.body.value);
However, it seems that for either of these solutions to work you also need to set your schema's strict mode to "false", since we are working with a dynamic key value.
Example:
var predictionSchema = new mongoose.Schema({
day: {
type: Number,
required: true
},
prediction: {
type: Number,
required: true
},
analysis: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Analysis', // Reference the Analysis Schema
required: true
}
}, { strict: false });

Mongoose - Query a nested property of Schema.Type.Mixed as a specified data type (Date)

I have a schema setup in Mongoose with
var MySchema = new Schema({
data: {
type: Schema.Types.Mixed
}
});
My issue is that on this 'data' object i am storing a date value as a nested property, it all works fine until i try and do a find() query with Mongoose and search using the nested field. Because Mongoose doesn't know it is a Date it cant use the usual '$gte', '$lte' and similar operators im guessing because it sees that data as just a String.
One of my objects looks similar to this
{
title:"My object",
data:{
publishDate: "2016-07-12T05:00:48.985Z"
}
Is there anyway that i can explicitly tell Mongoose to expect the value to be a date so i can use '$gte' as an operator?
Model.find({
"data.publishDate":{
$gte:new Date()
}
})
Turns out i had to strictly type the value as a date before saving to the database. Otherwise the date operators '$gte', '$lte' etc would not work.
Solution is to do this
{
title:"My object",
data:{
publishDate: new Date("2016-07-12T05:00:48.985Z")
}
At this point i don't believe you can type the data dynamically when running a query.

node.js: limit number of object Ids that an array contain in mongodb using mongoose

May be my question is so simple but I'm not finding a solution for it.
I want to limit the size of array of object Ids in mongodb. I'm using mongoose.
how to do this using mongoose schema?
or The solution I'm thinking is first retrieve the document then calculate the size of array and after that return the validation failure error to the end user if it occurs.
Please help me find the better solution.
There's no such thing in Mongoose, but you can define your own validation. According to Mongoose documentation, you can do that:
var userSchema = new Schema({
phone: [{
type: ObjectId,
validate: {
validator: function() {
return this.phone.length <= 100;
},
message: 'Array exceeds max size.'
}
}]
});
For an array the validator function is called for each element with the element as parameter. But you can check the property's length instead of validating an element.
That will work when you update your model instance with the save method. Validators are not run when using User.update.

Mongoose : How to find documents in which fields match an ObjectId or a string?

This is mongoose DataModel in NodeJs
product: {type: mongoose.Schema.Types.ObjectId, ref: 'products', required: true}
But in DB, this field is having multiple type of values in documents, have String and ObjectId
I'm querying this in mongoose
{
$or: [
{
"product": "55c21eced3f8bf3f54a760cf"
}
,
{
"product": mongoose.Types.ObjectId("55c21eced3f8bf3f54a760cf")
}
]
}
But this is only fetching the documents which have that field stored as ObjectId.
Is there any way that it can fetch all the documents having both type of values either String OR ObjectId?
Help is much appreciated. Thanks
There is a schema in Mongoose, so when you query a document, it will search it by this schema type. If you change the model's product type to "string", it will fetch only documents with string IDs.
Even if there is a way to fetch either a string OR ObjectId, it's smelly to me to have such inconsistency.
I've encountered the same problem, so the solution was to standardize all documents by running a script to update them.
db.products.find().forEach(function(product) {
db.products.update({ type: product.type},{
$set:{ type: ObjectId(data.type)}
});
});
The only problem I see there is if this type field is actually an _id field. _id fields in MongoDB are immutable and they can't be updated. If that is your case, you can simply create a new document with the same (but parsed) id and remove the old one.
This is what I did: (in Robomongo)
db.getCollection('products').find().forEach(
function(doc){
var newDoc = doc;
newDoc._id = ObjectId(doc._id);
db.getCollection('products').insert(newDoc);
}
)
Then delete all documents, which id is a string:
db.getCollection('products').find().forEach(
function(doc){
db.getCollection('products').remove({_id: {$regex: ""}})
}
)
There is another way to do this. If we Update the type to Mixed then it will fetch all the documents with each type, either String or ObjectId
Define this in your Schema
mongoose.Schema.Types.Mixed
Like
product: {type: mongoose.Schema.Types.Mixed, required: true}

Mongoose - find all documents whose array property contains a given subset?

I have a (simplified) model based on the following schema:
schema = mongoose.Schema({
foo: { type: String },
bars: [{ type: String }]
});
model = mongoose.model ('model', schema);
and I want to create an API to return all documents that contain all of the 'bars' which are provided in a comma separated list. So I have:
exports.findByBars = function (req, res) {
var barsToFind = req.body.bars.split(',');
// find the matching document
};
Does Mongoose provide an API for this or is there a query param I can pass to Model#find to get this functionality? I only want a document to be returned if its bar property contains all of the values in the barsToFind array.
There are ways to structure your query to do this, the approaches are different depending on your mongodb server version. So following on from your code:
For MongoDB version 2.6 and above, use the $all operator:
model.find({
"bars": { "$all": barsToFind }
},
And though the operator does exist for previous versions, it behaves differently so you actually need to generate an $and statement to explicitly match each entry:
var andBars = [];
barsToFind.forEach(function(bar) {
andBars.push({ "bars": bar })
});
model.find({
"$and": andBars
},
Both ensure that you only match documents that contain all of the entries in the array as you have specified, it's just that the syntax available to MongoDB 2.6 is a little nicer.

Resources