I am using mongodb and sails/waterlinejs
One of my documents has a field "participants": ["1" ,"2" ,"3"]
I would like to make a mongodb query:
Document.find({participants: {$all: ["1", "2"]}})
But I notice that if I do it in waterline, it returns me all the documents that contains EITHER "1" OR "2".
I would like to get BOTH "1" AND "2"
Is this something that I have to do in native query? Does waterline have a doc somewhere that lists all the available operators for .find()?
Thanks
Try to use $and, You should do like this.
query = Model.where({"$and": [ { "participants": "1" }, { "participants": "2" } ] });
Related
I have an entry like below,
[
{
"_id":ObjectId("59ce020caa87df4da0ee2c78"),
"name": "Tom",
"owner_id": ObjectId("59ce020caa87df4da0ee2c78")
},
{
"_id":ObjectId("59ce020caa87df4da0ee2c79"),
"name": "John",
"owner_id": ObjectId("59ce020caa87df4da0ee2c78")
}
]
now, I need to find the person whose _id is equal to owner_id using find() in MongoDB.
Note, we can't not use $match (aggregation) due to some reason.
I am using this query,
db.people.find({ $where: "this._id == this.owner_id" })
but, it's not returning the expected output. Can anyone help me with this.
Thanks.
Using $expr and $eq you can get desired values avoiding the use of $where into a find stage (not aggregation necessary).
db.collection.find({
"$expr": {
"$eq": [
"$_id",
"$owner_id"
]
}
})
I am beginner in MongoDB and struck at a place I am trying to fetch data from nested array but is it taking so long time as data is around 50K data, also it is not much accurate data, below is schema structure please see once -
{
"_id": {
"$oid": "6001df3312ac8b33c9d26b86"
},
"City": "Los Angeles",
"State":"California",
"Details": [
{
"Name": "Shawn",
"age": "55",
"Gender": "Male",
"profession": " A science teacher with STEM",
"inDate": "2021-01-15 23:12:17",
"Cars": [
"BMW","Ford","Opel"
],
"language": "English"
},
{
"Name": "Nicole",
"age": "21",
"Gender": "Female",
"profession": "Law student",
"inDate": "2021-01-16 13:45:00",
"Cars": [
"Opel"
],
"language": "English"
}
],
"date": "2021-01-16"
}
Here I am trying to filter date with date and Details.Cars like
db.getCollection('news').find({"Details.Cars":"BMW","date":"2021-01-16"}
it is returning details of other persons too which do not have cars- BMW , Only trying to display details of person like - Shawn which have BMW or special array value and date too not - Nicole, rest should not appear but is it not happening.
Any help is appreciated. :)
A combination of $match on the top-level fields and $filter on the array elements will do what you seek.
db.foo.aggregate([
{$match: {"date":"2021-01-16"}}
,{$addFields: {"Details": {$filter: {
input: "$Details",
as: "zz",
cond: { $in: ['BMW','$$zz.Cars'] }
}}
}}
,{$match: {$expr: { $gt:[{$size:"$Details"},0] } }}
]);
Notes:
$unwind is overly expensive for what is needed here and it likely means "reassembling" the data shape later.
We use $addFields where the new field to add (Details) already exists. This effectively means "overwrite in place" and is a common idiom when filtering an array.
The second $match will eliminate docs where the date matches but not a single entry in Details.Cars is a BMW i.e. the array has been filtered down to zero length. Sometimes you want to know this info so if this is the case, do not add the final $match.
I recommend you look into using real dates i.e. ISODate instead of strings so that you can easily take advantage of MongoDB date math and date formatting functions.
Is a common mistake think that find({nested.array:value}) will return only the nested object but actually, this query return the whole object which has a nested object with desired value.
The query is returning the whole document where value BMW exists in the array Details.Cars. So, Nicole is returned too.
To solve this problem:
To get multiple elements that match the criteria you can do an aggregation stage using $unwind to separate the different objects into array and match by the criteria you want.
db.collection.aggregate([
{
"$match": { "Details.Cars": "BMW", "date": "2021-01-26" }
},
{
"$unwind": "$Details"
},
{
"$match": { "Details.Cars": "BMW" }
}
])
This query first match by the criteria to avoid $unwind over all collection.
Then $unwind to get every document and $match again to get only the documents you want.
Example here
To get only one element (for example, if you match by _id and its unique) you can use $elemMatch in this way:
db.collection.find({
"Details.Cars": "BMW",
"date": "2021-01-16"
},
{
"Details": {
"$elemMatch": {
"Cars": "BMW"
}
}
})
Example here
You can use $elemenMatch into query or projection stage. Docs here and here
Using $elemMatch into query the way is this:
db.collection.find({
"Details": {
"$elemMatch": {
"Cars": "BMW"
}
},
"date": "2021-01-16"
},
{
"Details.$": 1
})
Example here
The result is the same. In the second case you are using positional operator to return, as docs says:
The first element that matches the query condition on the array.
That is, the first element where "Cars": "BMW".
You can choose the way you want.
db.getCollection('test').update({
"b_id": "3"
},
{
"$push": {"books": {
"status": "available",
"shelf_id": "$shelf_id",
"rack_no": "$rack_no",
"book_id": new ObjectId()
}
}
})
shelf_id and rack_no are already available in the document. Here, I need to create the array "books" which includes status, shelf_id, rack_no and book_id.
I am not able to get the existing value of shelf_id and rack_no in this case. It considers $rack_id as string instead the value from the document. Please suggest a way.
Yes, you can do that in MongoDB 4.2, using the pipeline form of update, but not with $push.
Passing an array of pipeline stages as the second argument to update will allow you to use aggregation operators.
The $push aggregation operator behaves very differently from the $push update operator, so in a pipeline use $set with $concatArrays, like:
db.getCollection('test').update({
"b_id": "3"
},
[{$set:
{
books: {$concatArrays:[
"$books",
[{
"status": "available",
"shelf_id": "$shelf_id",
"rack_no": "$rack_no",
"book_id": new ObjectId()
}]
]}
}
}])
I've a bunch of documents that look like:
{
"ids": [{"name":"aa", "age":1}, {"name":"bb", "age":2}]
}
I'd like to be able to query my documents providing a collection of ids, something like
db.getCollection('Collection').find({"ids":{$in : [{"name":"aa", "age":1}, {"name":"bb", "age":2}]}})
Generally that works, however it breaks when the fields order is changed, so for example I cannot find documents when I execute the following query
db.getCollection('Collection').find({"ids":{$in : [{"age":1,"name":"aa"}, { "age":2, "name":"bb"}]}})
I know that I could try to always execute a query with fields "in order", but from my current task perspective it's not always possible. Any help with that ?
You need $elemMatch when you want to run your query against an array of objects:
db.col.find({ $or: [ { "ids": { $elemMatch: {"age":1,"name":"aa"} } }, { "ids": { $elemMatch: { "age":2, "name":"bb"} } } ] })
Mongo Playground
EDIT: you can decide whether $or or $and should be a top level operator (depending on your use case)
Is it possible to use something like 'exists' in a Mongo query to return this record based on an ID?
Something like select where 'ids' contains key '123456'?
{
"department": "Digging",
"ids": {
"123456": {
"color": "blue"
},
"123457": {
"color": "red"
}
}
}
As you're searching for the existence of a field with a given name, $exists is the operator you need (see Advanced Queries).
e.g. something like:
db.YourCollection.find({ "ids.123456" : {$exists: true}});