I have a document collection with recipes that looks like this:
{
"title" : "Pie",
"url" : "pie.png",
"people" : "4",
"ingredients" : [
{
"amount" : "150",
"measure" : "g",
"name" : "Butter"
},
{
"amount" : "200",
"measure" : "g",
"name" : "Flour"
}
],
"_id" : ObjectId("55acf33223ae282719bdc9b7")
}
Im trying to create a query that retrieves all the documents that contains multiple fields, like "butter" and "flour".
I have managed to retrieve documents that contains one field, like the query below:
db.recipe.find(
{"ingredients.name": "Butter"},
{"_id": 1, "ingredients": {"$elemMatch": {"name": "Butter"}}},
callback
);
I’ve tried using
{
$all: [
{ $elemMatch: { name: "Butter" }},
{ $elemMatch:{ name: "Flour"}}
]
}
but I cant get it to work. Any help appreciated!
How about this:
db.recipe.find({
"$and": [
{ "ingredients.name": "Butter" },
{ "ingredients.name": "Flour" }
]
})
EDIT(thanks to #BlakesSeven):
The shorter way to write the above is using the $all operator.
db.recipe.find({ "ingredients.name": { "$all": ["Butter", "Flour"] } }
Related
I have MongoDB collection with multiple records. Each record has an array which contains objects with multiple fields.
I have collection like below:
[{
"name" : "Karthik Thurairaja"
"universities" : [
{
"name" : "Anna University",
"city" : "Chennai"
},
{
"name" : "Punjab University",
"city" : "Chandigarh"
},
{
"name" : "University of Delhi",
"city" : "New Delhi"
}
],
},
{
"name" : "Sathish Kumar"
"universities" : [
{
"name" : "Anna University",
"city" : "Chennai"
},
{
"name" : "University of Hyderabad",
"city" : "Hyderabad"
},
{
"name" : "University of Delhi",
"city" : "New Delhi"
}
],
}]
I need to find all the records universities city is equal to Chennai.
I have tried query like below:
Collection.find({ universities.city : "Chennai" }).exec(...);
You can use an $elemMatch query to achieve this.
Collection.find({ universities: { $elemMatch: { city: "Chennai" } } }).exec(...);
I have the following document structure in my MongoDB and I am trying to return an array of objects containing all prices for itemID "5a59c587fa9b4a212b0a1312" across all documents using the following query but unfortunately it is always returning an empty array. Can someone please advice what I might be doing wrong here? and how I can get such a result?
Note: I am using promised-mongo in a Node.js app to access my MongoDB
Query I tried:
{ transDetails: { $elemMatch: { itemID: "5a59c587fa9b4a212b0a1312" } } }
DB sample:
{
"_id" : ObjectId("5a688e7ea52deb6d4a6b6663"),
"transactionID" : "1",
"transDetails" : [
{
"itemID" : "5a59c587fa9b4a212b0a1312",
"price" : "22"
},
{
"itemID" : "5a59c95b081c6c612bd17058",
"price" : "24"
}
] }
{
"_id" : ObjectId("5a6aa99a52deb6d4a67714"),
"transactionID" : "2",
"transDetails" : [
{
"itemID" : "5a59c587fa9b4a212b0a1312",
"price" : "35"
},
{
"itemID" : "5a59c95b081c6c612bd17058",
"price" : "24"
}
] }
Find with projection to have only matched items in the transDetails:
.find({"transDetails.itemID": "5a59c587fa9b4a212b0a1312"}, {_id:0, "transDetails.$": 1})
Will return
{
"transDetails" : [
{
"itemID" : "5a59c587fa9b4a212b0a1312",
"price" : "22"
}
]
},
{
"transDetails" : [
{
"itemID" : "5a59c587fa9b4a212b0a1312",
"price" : "35"
}
]
},
....
Wish you re-shape the documents, you can use aggregation:
.aggregate([
{ $match: { "transDetails.itemID": "5a59c587fa9b4a212b0a1312" } },
{ $project: {
_id: 0,
transDetails: {
$filter: {
input: "$transDetails",
as: "item",
cond: { $eq: [ "$$item.itemID", "5a59c587fa9b4a212b0a1312" ] }
}
}
} },
{ $unwind: "$transDetails"},
{ $project: {price: "$transDetails.price"}}
])
Which will give you
{
"price" : "22"
},
{
"price" : "35"
},
...
i am not able to query results in this query,
i want result based on detail.type (like fetch record where detail.type="one") and fetch only first 10 records in detail.numbers array
{
"_id" : ObjectId("5a27b609e101b6092b4ebf91"),
"city" : "Mumbai",
"detail" : [
{
"type" : "One",
"name" : "Some name",
"_id" : ObjectId("5a27b609e101b6092b4ebf92"),
"numbers" : [
"72598xxx78",
"81301xxx88",
"83302xxx30",
"84309xxx43",
"85309xxx77",
"86309xxx61",
"87270xxx88",
"85272xxx36",
"88272xxx23",
"85276xxx01"
]
},
{
"name" : "Some name",
"type" : "two",
"_id" : ObjectId("5a28e954d4f5a30527d92a32"),
"contact" : [
"72598xxx78",
"81301xxx88",
"83302xxx30",
"84309xxx43",
"85309xxx77",
"86309xxx61",
"87270xxx88",
"85272xxx36",
"88272xxx23",
"85276xxx01"
]
},
]
}
MongoDB facilitates querying over array elements using $elemMatch operator.
According to description as mentioned into above question as a solution to it please try executing following MongoDB query to fetch required data from MongoDB collection.
db.collection.find({
detail: {
$elemMatch: {
type: 'One'
}
}
}, {
_id: 1,
city: 1,
'detail.$': 1
})
db.collection.aggregate([
{
$project:{
detail:{
$map:{
input:{$filter:{input:"$detail",as:"d",cond:{$eq:["$$d.type","One"]}}},
as:"d",
in:{
"type" : "$$d.type",
"name" : "$$d.name",
"numbers":{$slice:["$$d.numbers",10]}
}
}
}
}
}
])
Here is an example of a nested document that I have in my collection:
"person" : [
{
"title" : "front-end developer",
"skills" : [
{
"name" : "js",
"project" : "1",
},
{
"name" : "CSS",
"project" : "5",
}
]
},
{
"title" : "software engineer",
"skills" : [
{
"name" : "Java",
"project" : "1",
},
{
"name" : "c++",
"project" : "5",
}
]
}
]
Is there a simple way of determining whether other documents are identical to this object e.g. has the same keys, value and array indexes? Currently my method of checking for duplicates is very long and requires multiple nested loops. Any help would be greatly appreciated. Thanks!
If you want to get a list of identical (except for the _id field, obviously) documents in your collection, here is how you can do that:
collection.aggregate({
$project: {
"_id": 1, // keep the _id field where it is anyway
"doc": "$$ROOT" // store the entire document in the "doc" field
}
}, {
$project: {
"doc._id": 0 // remove the _id from the stored document because we do not want to compare it
}
}, {
$group: {
"_id": "$doc", // group by the entire document's contents as in "compare the whole document"
"ids": { $push: "$_id" }, // create an array of all IDs that form this group
"count": { $sum: 1 } // count the number of documents in this group
}
}, {
$match: {
"count": { $gt: 1 } // only show what's duplicated
}
})
As always with the aggregation framework, you can try to make sense of what exactly is going on in each step by commenting out all steps and then activating everything again stage by stage.
My mongo table contains contains collection 'Shops' and data like the below:
{
"ShopId" : 9999,
"products" : [
{
"productId" : "1234",
"productName" : "abcd",
},
{
"productId" : "5678",
"productName" : "abc",
},
{
"productId" : "2345",
"productName" : "def",
}
],
}
There will be several shops in the table having a list of products.
Requirement:
I want to fetch the records having shopId=9999 and products matches the string abc
My query
model.Shops.aggregate([{$match:{"ShopId":9999}},{$project:{products:{$filter:{input:'$products',cond: {'productName':/abc/ }}}}}])
Problem:
It is fetching the productname:defwith the other data that matches productname:abc.
You can't use regex search with the $filter operator. The only way to achieve this is to unwind products, filter document and then re-group them in an array
model.Shops.aggregate([
{
$match:{
"ShopId":9999
}
},
{
$unwind:"$products"
},
{
$match:{
"products.productName":/abc/
}
},
{
$group:{
_id:null,
products:{
$push:{
"productName":"$products.productName",
"productId":"$products.productId"
}
}
}
}
])
output:
{
"_id":null,
"products":[
{
"productName":"abcd",
"productId":"1234"
},
{
"productName":"abc",
"productId":"5678"
}
]
}
to use it with a variable, declare your regex like this:
var regex: /abc/;
and then use it directly in the query
$match:{
"products.productName": regex
}
Below code worked on mongoshell for me, and your code was giving error to me, that Missing 'as' parameter to $filter.
db.Shops.aggregate([
{$match:{"ShopId":9999}},
{$project:{
products:{$filter:{input:'$products',as:"product",cond: { $eq: [ "$$product.productName", "abc" ] }}}
}}
])