Can we use $in and $nin together in a Mongoose query? [duplicate] - node.js

I have a MongoDB collection with records having a "name" field, I am trying to perform a find query where the name field appears twice in the query. I want to exclude certain names, via $nin, and perform regex search for other names. It doesn't seem to be working, as it returns all records. If I just have the regex search or the $nin search, it works as expected.
db.users.find({name:{$nin:[current_user]}).cb(array) - works
db.users.find({name:new RegExp(/query/)}).cb(array) - works
db.users.find({name:{$nin:[current_user]}, name:new RegExp(/query/)}).cb(array) - does NOT work, the current_user is NOT excluded from the find result.
I have a feeling, the find command takes the last query for multiple occurrences of the same field, is that so? And how do I get around it?
Thanks for help,
Gary

Your query JSON object contains name field two times, and it breaks the query. Pay attention to the $and mongo query operator. There are two ways to construct correct query:
1) db.users.find({ $and: [{ name: { $nin: [current_user] } }, { name: { $regex: new RegExp(/query/) } }] })
2) db.users.find({ name: { $nin: [current_user], $regex: new RegExp(/query/) } })
Also, if you exclude only one user, you can use $ne operator instead of $nin.

Related

mongodb get list of subdocuments that matched with list of values

my document schema goes like this
_id: kkj33h2kjkjh32jk34
events: [
{
_id: k234j3lk4k2j3h4j3j4
},
{
_id: k234j3lk4k2j3h4j3j4
},
{
_id: k234j3lk4k2j3h4j3j4
}
]
here is my query, I have a list of _ids of the subdocuments of events field and I need to get all the matched subdocuments as the response from the event field I have tried to use $in and many but failed can anyone suggest me how to do this
tried this
subarr=['fh576hgfu658uyg7h','k234j3lk4k2j3h4j3j4']
model.findOne({
clgid: req.query.clgid,
'events._id': {$in:subarr}
},{"events.$":1});
but the problem with the above code is that it is fetching the first matching subdocument. but I need all the matching subdocuments.
suggest me the right way to do this query so that I get all the matched subdocuments that match from array
The issue of your query matching only the first subdocument is the use of {"events.$":1} in your projection.
I'm not sure what you are actually intending to do.
{"events.$":1} will limit to the first (sub)document matching your query, as per the documentation of the $ operator.
Maybe you're trying only to get the _id of the subdocuments and then, please try the following:
subarr=['fh576hgfu658uyg7h','k234j3lk4k2j3h4j3j4']
model.findOne({
clgid: req.query.clgid,
'events._id': {$in:subarr}
},{"events._id":1});

Differences between $or and $in when querying Strings in MongoDB / mongoose

While building an API, I need to match documents that contain pending or active values for the key status.
When trying
args.status = {
$or: [
'active',
'pending'
]
}
I get an error: cannot use $or with string
However,
args.status = {
$in: [
'active',
'pending'
]
}
works just fine.
I would expect $or to work here. Can someone provide context on the differences between the two and why Strings require $in?
$or performs the logical OR operation on an ARRAY with more than two expressions e.g. {$or:[{name:"a"},{name:"b"}]} This query will return the record which are having either name 'a' or 'b'.
$in works on the array and return the documents which are which contains any of the field from your specified array e.g.{name:{$in:['a','b']}} This query will return the documents where name is either 'a' or 'b'.
Ideally both are doing same but just having the syntax difference.
In your case you have to modify your OR query syntax and add the condition expessions in an ARRAY.
{ $or: [
{
"args.status": "active"
},
{
"args.status": "pending"
}
]
}
Thats because $or expects array of objects. Objects that defines some filters out of which at least one needs to be match to return the result. For your particular scenario $in is the best option. Still if you wanna go with $or, the query will be like:
{
$or: [
{'args.status' : {$eq: 'active'}},
{'args.status' : {$eq: 'pending'}}
]
}
I'd suggest you stick with $in as it is the best fit for your requirement.
You can check the official docs for more details on $or
Hope this helps :)

Mongo Query to search one or more values are present in an array field of a document

I have a collection like below
{
_id: ObjectId(),
account_number: someID,
account_context: {acnt_id:"1234",acnt_name:"Akhil",address:"Kadapa"},
tags:["tag","TaG","User","tag2","usr"]
},
{
_id: OBjectId(),
account_number: someID,
account_context: {acnt_id:"1234",acnt_name:"Akhil",address:"Kadapa"},
tags:["gat","GaT","Hello","tag2","Usr"]
}
I would like to query based on tags.
If I search for "tag" and "gat" , I should get both the documents
If I search for "Tag" , I should get first document
If I search for "tag" and "Hello", I should get both the documents.
Which means if the search field match for any one of the array element in the document I should get that document.
How can I get that?
you can use $elemMatch with $in for this problem like it:
var searchedArray = ["tag","Hello"]
collection.find({
tags: {$elemMatch: {$in:searchedArray}}
}, (err, result)=>{
})
$elemMatch check all elements of an array with her expression. my expression is $in that check filed with all values is there in searchedArray if equal accept it.

Mongoose Query: compare two values on same document

How can I query a Mongo collection using Mongoose to find all the documents that have a specific relation between two of their own properties?
For example, how can I query a characters collections to find all those characters that have their currentHitPoints value less than their maximumHitPoints value? Or all those projects that have their currentPledgedMoney less than their pledgeGoal?
I tried to something like this:
mongoose.model('Character')
.find({
player: _currentPlayer
})
.where('status.currentHitpoints').lt('status.maximumHitpoints')
.exec(callback)
but I am getting errors since the lt argument must be a Number. The same goes if I use $.status.maximumHitpoints (I was hoping Mongoose would be able to resolve it like it does when doing collection operations).
Is this something that can be done within a Query? I would expect so, but can't find out how. Otherwise I can filter the whole collection with underscore but I suspect that is going to have a negative impact on performance.
PS: I also tried using similar approaches with the find call, no dice.
MongoDB 3.6 and above supports aggregation expressions within the query language:
db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )
https://docs.mongodb.com/manual/reference/operator/query/expr/
Thanks to Aniket's suggestion in the question's comments, I found that the same can be done with Mongoose using the following syntax:
mongoose.model('Character')
.find({
player: _currentPlayer
})
.$where('this.status.currentHitpoints < this.status.maximumHitpoints')
.exec(callback)
Notice the $where method is used instead of the where method.
EDIT: To expand on Derick's comment below, a more performance sensitive solution would be to have a boolean property inside your Mongoose schema containing the result of the comparison, and update it everytime the document is saved. This can be easily achieved through the use of Mongoose Schema Plugin, so you would have something like:
var CharacterSchema = new mongoose.Schema({
// ...
status: {
hitpoints: Number,
maxHitpoints: Number,
isInFullHealth: {type: Boolean, default: false}
}
})
.plugin(function(schema, options) {
schema.pre('save', function(next) {
this.status.isInFullHealth = (this.status.hitPoints >= this.status.maxHitpoints);
next();
})
})
mongoose.model('Character')
.find({
player: _currentPlayer, $expr: { $lt: ['$currentHitpoints', '$maximumHitpoints'] }
})
This above query means find the record which has currentHitpoints less than maximumHitpoints
Starting in MongoDB 5.0, the $eq, $lt, $lte, $gt, and $gte comparison operators placed in an $expr operator can use an index on the from collection referenced in a $lookup stage.
Example
The following operation uses $expr to find documents where the spent amount exceeds the budget:
db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )

How to use same field multiple times in MongoDB find query in NodeJS

I have a MongoDB collection with records having a "name" field, I am trying to perform a find query where the name field appears twice in the query. I want to exclude certain names, via $nin, and perform regex search for other names. It doesn't seem to be working, as it returns all records. If I just have the regex search or the $nin search, it works as expected.
db.users.find({name:{$nin:[current_user]}).cb(array) - works
db.users.find({name:new RegExp(/query/)}).cb(array) - works
db.users.find({name:{$nin:[current_user]}, name:new RegExp(/query/)}).cb(array) - does NOT work, the current_user is NOT excluded from the find result.
I have a feeling, the find command takes the last query for multiple occurrences of the same field, is that so? And how do I get around it?
Thanks for help,
Gary
Your query JSON object contains name field two times, and it breaks the query. Pay attention to the $and mongo query operator. There are two ways to construct correct query:
1) db.users.find({ $and: [{ name: { $nin: [current_user] } }, { name: { $regex: new RegExp(/query/) } }] })
2) db.users.find({ name: { $nin: [current_user], $regex: new RegExp(/query/) } })
Also, if you exclude only one user, you can use $ne operator instead of $nin.

Resources