Matched elements from mongodb records - mongodb

Suppose I have following documents in my collection
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"tags" : [
{
"tagName" : "fun",
"created" : ISODate("2016-01-22T06:13:56.510Z")
},
{
"tagName" : "cool",
"created" : ISODate("2016-01-22T06:13:56.509Z")
},
{
"tagName" : "good",
"created" : ISODate("2016-01-22T06:13:56.509Z")
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"tags" : [
{
"tagName" : "super",
"created" : ISODate("2016-01-22T06:13:56.509Z")
},
{
"tagName" : "fun",
"created" : ISODate("2016-01-22T06:13:56.509Z")
}
]
}
I want to search relative tags and want to display tag array only.
How can I query to get the list of tag names?

To only query a specific field in MongoDB you can use the find method with the projection parameter:
https://docs.mongodb.org/manual/reference/method/db.collection.find/
db.test.find({}, {"tags.tagName":1,"_id":0}).pretty()
{
"tags" : [
{
"tagName" : "fun"
},
{
"tagName" : "cool"
},
{
"tagName" : "good"
}
]
}
The first parameter is blank {} because you don't have any query and the second parameter is your projection. With an embedded document you have to use the dot notation "tags.tagName". The "_id":0 to not display the _id field.

Related

Search array for dates within a range

I am new to MongoDB, keep that in mind as I ask my questions please. I have the following collection named 'documents' where I have an array named attributes which contains key:value pairs of different types.
{
"_id" : ObjectId("5d376c67f6c305c7571f7dd7"),
"name" : "testContract.pdf",
"fileType" : "pdf",
"attributes" : [
{
"abc" : 1
},
{
"def" : ISODate("2012-12-01T08:00:00Z")
},
{
"ghi" : "test"
}
]
}
{
"_id" : ObjectId("5d376ca4f6c305c7571f7dd8"),
"name" : "1099.pdf",
"fileType" : "pdf",
"attributes" : [
{
"def" : ISODate("2012-06-03T07:00:00Z")
},
{
"ghi" : "taxes"
}
]
}
What I would like to do is return one or more documents from this collection that fit within a date range. For example I can return all documents that have a fileType of 'pdf' with the following query -->
db.documents.find({"fileType":"pdf"});
But what I am trying to figure out is can I search an array containing different data types like dates in a range successfully while also being able to search for strings. I can also search the attributes array with the following -->
db.documents.find({"attributes":{"ghi":"test"}});
Here is an example of what I am trying to get but it is not working...
db.documents.find({'attributes':$match:{[{'def':{$gte:new Date('2011-11-30')}}]}});
Is something like this what you are looking for?
Based on the following documents:
{
"_id" : ObjectId("5d38aad64850fbd5d13f14bd"),
"name" : "testxx.pdf",
"attributes" : [
{
"abc" : 1
},
{
"def" : ISODate("2012-12-01T08:00:00Z")
},
{
"ghi" : "test"
}
]
}
{
"_id" : ObjectId("5d38b0eae4adbe945b6cbb89"),
"name" : "testyy.pdf",
"attributes" : [
{
"abc" : 2
},
{
"def" : ISODate("2013-12-01T08:00:00Z")
},
{
"ghi" : "test1"
}
]
}
{
"_id" : ObjectId("5d38b12f21e647b8d384d841"),
"name" : "testzz.pdf",
"attributes" : [
{
"abc" : 3
},
{
"def" : ISODate("2012-05-01T08:00:00Z")
},
{
"ghi" : "test"
}
]
}
Query def > 2010/11/30 - returns all 3 docs above
db.chkdates.find({'attributes.def':{$gte:new Date(2010,11,30)}}).pretty()
Adding another key/value pair and range looks like:
db.chkdates.find({'attributes.def':{$gte:new Date(2011,12,12),
$lte:new Date(2012,10,12)},
'attributes.ghi':'test'}).pretty()
Returns only 1 document:
{
"_id" : ObjectId("5d38b12f21e647b8d384d841"),
"name" : "testzz.pdf",
"attributes" : [
{
"abc" : 3
},
{
"def" : ISODate("2012-05-01T08:00:00Z")
},
{
"ghi" : "test"
}
]
}
You can use the $gte and $lte for querying within a date range. It would look something like this:
{'def': { $gte: qryDateFrom, $lte: qryDateTo }}
Depending on if you're using aggregate pipleline or a regular mongoose query, you'd just apply this accordingly.
For instance, using $match in an aggregate with a string match included, it would look like this:
$match: {
$and: [
{'id': { $ne: req.user._id }},
{'def': { $gte: qryDateFrom, $lte: qryDateTo }}
]
}

MongoDB - query for a nested item inside a collection

i have a mongodb collection "result" with data like
{ "_id" : {
"user" : "Howard",
"friend" : "Sita"
},
"value" : {
"mutualFriend" :[ "Hanks", "Bikash", "Shyam", "Bakshi" ]
}
}
{ "_id" : {
"user" : "Shiva",
"friend" : "Tom"
},
"value" : {
"friendList" :[ "Hanks", " Tom", " Karma", " Hari", " Dinesh" ]
}
}
{ "_id" : {
"user" : "Hari",
"friend" : "Shiva"
},
"value" : {
"mutualFriend" :[ "Tom", "Karma", "Dinesh" ]
}
}
Now, here i want to query whole Document having value.mutualFriend. how can i get the result?
Expected Output
{ "_id" : {
"user" : "Howard",
"friend" : "Sita"
},
"value" : {
"mutualFriend" :[ "Hanks", "Bikash", "Shyam", "Bakshi" ]
}
}
{ "_id" : {
"user" : "Hari",
"friend" : "Shiva"
},
"value" : {
"mutualFriend" :[ "Tom", "Karma", "Dinesh" ]
}
}
i have large number of document in MongoDB collection, containing value.friendList and value.mutualFriend and then i want to find only documents with value.mutualFriend
db.collection.find({"value.mutualFriend.0" : { $exists : true }})
Its just make sure that the 0th element exists. you can customize your query over various array length.

Mongo: how to retrieve ONLY subdocs that match certain properties

Having, for example, a collection named test and the following document is inside:
{
"_id" : ObjectId("5692ac4562c824cc5167379f"),
"list" : [
{
"name" : "elem1",
"type" : 1
},
{
"name" : "elem2",
"type" : 2
},
{
"name" : "elem3",
"type" : 1
},
{
"name" : "elem4",
"type" : 3
},
{
"name" : "elem4",
"type" : 2
}
]
}
Let's say I would like to retrieve a list of only those subdocuments inside list that match:
type = 2.
I've tried the following query:
db.getCollection('test').find({
'_id': ObjectId("5692ac4562c824cc5167379f"),
'list.type': 1
})
But the result I get contains every subdocument inside list, and I guess this is because inside list there are at least one document which's type equals 1.
Instead of that, the result I am interested to obtain would be every subdocument inside list that matches 'list.type': 1:
{
"_id" : ObjectId("5692ac4562c824cc5167379f"),
"list" : [
{
"name" : "elem1",
"type" : 1
},
{
"name" : "elem3",
"type" : 1
}
]
}
...so $and $elemMatch is not what I am really looking for as they return just the first matching element.
Anyone knows how to achieve what I am looking for?
db.myCol.aggregate([
{ $unwind: "$list" },
{ $match: { "list.type":1 } },
{ $group: { "_id":"$_id", list: {$push:"$list"}} }
])

MongoDB Aggregation Projection

If I have a collection as follows:
db.cafe.insert({name: "Cafe1", customers: [{name: "David", foods: [{name : "cheese"}, {name: "beef"}]}, {name: "Bill", foods: [{name: "fish"}]} ]})
db.cafe.find().pretty()
{
"_id" : ObjectId("54f5ae58baed23b7a34fccb6"),
"name" : "Cafe1",
"customers" : [
{
"name" : "David",
"foods" : [
{
"name" : "cheese"
},
{
"name" : "beef"
}
]
},
{
"name" : "Bill",
"foods" : [
{
"name" : "fish"
}
]
}
]
}
How can I extract an array containing just the food objects for people called "David".
Desired output is just the array of foods, i.e:
[{name: "cheese"}, {name: "beef"}]
I have tried an aggregation pipeline that unwinds the cafes customers, then matches on name then projects the food, e.g:
db.cafe.aggregate( [{$unwind : "$customers"}, {$match : {"customers.name": "David"}}, {$project : {"customers.foods": 1, _id : 0}
}] ).pretty()
{
"customers" : {
"foods" : [
{
"name" : "cheese"
},
{
"name" : "beef"
}
]
}
}
This seems close to the desired result, however, I'm left with the issue that the foods I want are referenced as an array under the property customers.foods. I would like the result to directly be:
[
{
"name" : "cheese"
},
{
"name" : "beef"
}
]
is there a way I can achieve the desired output?
You are doing your projection wrong.
db.cafe.aggregate( [
{ "$match" : { "customers.name": "David" }},
{ "$unwind" : "$customers" },
{ "$project" : { "foods": "$customers.foods", "_id": 0 }}
])
Output
{ "foods" : [ { "name" : "cheese" }, { "name" : "beef" } ] }
You can also get (something very, very close to) your desired output with a regular query:
> db.cafe.find({ "customers.name" : "David" }, { "customers.$.foods" : 1, "_id" : 0 })
{ "customers" : [ { "name" : "David", "foods" : [ { "name" : "cheese" }, { "name" : "beef" } ] } ] }
Customers will be an array containing just the first object with name : "David". You should prefer this approach to the aggregation as it's vastly more performant. You can extract the foods array in client code.

MongodDB retrieve a subdocument by the property name

My document looks like:
{ "entity_id" : 2,
"features" :
[
{ "10" : "name" },
{ "20" : "description" },
... ,
{ "90" : "availability" }
]
}
I would like to, knowing 2 things: the value of "entity_id" (2), and the value of the property in one of the elements of the "features" array, to retrieve only the subdocument
{ "20" : "description" }
in one query. Many thanks!
If you want to get only a part of the whole document, use so called Projection operators
See examples below:
> db.collection.find().pretty()
{
"_id" : ObjectId("52e861617acb7ce761e64a93"),
"entity_id" : 2,
"features" : [
{
"10" : "name"
},
{
"20" : "description"
},
{
"90" : "availability"
}
]
}
Projection operators are specified in find() like here:
> db.collection.find({},{ features : { $elemMatch : { 20 : { $exists: true } }}}).pretty()
{
"_id" : ObjectId("52e861617acb7ce761e64a93"),
"features" : [
{
"20" : "description"
}
]
}
> db.collection.find({},{ entity_id : 1, features : { $elemMatch : { 20 : { $exists: true } }}}).pretty()
{
"_id" : ObjectId("52e861617acb7ce761e64a93"),
"entity_id" : 2,
"features" : [
{
"20" : "description"
}
]
}
> db.collection.find({},{ _id : 0, entity_id : 1, features : { $elemMatch : { 20 : { $exists: true } }}}).pretty()
{ "entity_id" : 2, "features" : [ { "20" : "description" } ] }
$elemMatch for projection is available in MongoDB since version 2.2.
Hope it solves your problem.