Complex query of MongoDB - mongodb

I have looked up the manual of MongoDB, but cannot find a proper solution to do the following search:
Document structure:
{
"_id" : ObjectId("57201082e92c07baef62452a"),
"user_id" : 1,
"profile" : [
{
"date" : ISODate("2012-10-11T12:58:06.000Z"),
"content" : [
{
"feature_id" : 1,
"feature_value" : true
}
]
},
{
"date" : ISODate("2013-04-12T8:23:09.000Z"),
"content" : [
{
"feature_id" : 1,
"feature_value" : false
}
]
}
]
}
What I want to get is the LATEST feature_value of a given user_id and a given feature_id.
Is there any way to accomplish this using MongoDB?
Thanks.

Assuming the latest(as profile.date) you can use the following to get the desired result.(query not tested, hope it works).
db.test.aggregate(
[
{$match : {"user_id" : 1}},
{$unwind : "$profile"},
{$unwind : "$profile.content"},
{$match : {"profile.content.feature_id" : 1}},
{$sort : {"profile.date" : -1}},
{$limit : 1},
{$group:{_id : "$_id", content : {$push:"$profile.content"}}}
])

Please try this:
db.test.aggregate(
{$match:{"user_id" :1,"profile.content.feature_id":1}},
{$project:{"profile.content.feature_value":1}},
{$sort:{"profile.date" :-1}},
{$limit : 1});

Related

mongodb aggregate,groupby list in object

I am looking at performing a group by upon a given value within a nest object. For example, my document structure is as follows:(Sorry about the limited data)
"_id" : "92623ba7-4ca5-46c7-8d76-c4bc8387ea00",
"Status" : 2.0,
"UploadDate" : ISODate("2018-10-30T12:01:19.619Z"),
"UpdateDate" : ISODate("2018-10-30T12:01:19.619Z"),
"Request" : "abc123",
"ShowCaseHtml" : "",
"PageResult" : [ ],
"ProductFilter" : {
"_id" : "9430fb88-2deb-4508-8422-dd67c3a35205",
"Status" : 2,
"UploadDate" : ISODate("2018-11-05T10:52:37.122Z"),
"UpdateDate" : ISODate("2018-11-05T10:52:37.122Z"),
"ProductPageType" : 0,
"Categories" : [ ],
"PriceRanges": [ ],
"Brands" : [ ],
"Sellers": [ ],
"StarRatings" : [ ],
},
"BreadCrumbs"[ ]
Result of my query returns only a part of object, what i need is full object but filterd version, here is my query
db.getCollection('dbName').aggregate(
{$match: {"Request": "abc123"}},
{$project :
{"PageResult":1,"ProductFilter":1,"BreadCrumbs":1,"ShowCaseHtml":1}},
{$unwind: "$PageResult"},
{$sort:{'PageResult.MarketPlaceProductPrice.ProductPrice':1}},
{$skip: 2},
{$limit: 3},
{$group: {"_id": "$_id", "PageResult": {$push: "$PageResult"}}},
{$project :
{"PageResult.MarketPlaceProductPrice.ProductPrice":1,"_id":0}}
)
Result of the query is like,
{
"PageResult" : [
{
"MarketPlaceProductPrice" : {
"ProductPrice" : 1519.00
}
},
{
"MarketPlaceProductPrice" : {
"ProductPrice" : 2749.00
}
},
{
"MarketPlaceProductPrice" : {
"ProductPrice" : 3359.00
}
}
]
}
i need the ProductFilter,BreadCrumbs and ShowCaseHtml areas too, that is why i specified the
{$project :
{"PageResult":1,"ProductFilter":1,"BreadCrumbs":1,"ShowCaseHtml":1}}
but i only have filtered PageResult area, any ideas ?
Using this query solved my problem
db.getCollection('dbName').aggregate(
{$match: {"Request":"abc123"}},
{$project : {"PageResult":1,"ProductFilter":1,"BreadCrumbs":1,"ShowCaseHtml":1}},
{$unwind: "$PageResult"},
{$sort:{'PageResult.MarketPlaceProductPrice.ProductPrice':1}},
{$skip: 2},
{$limit: 3},
{$group: {"_id": {"Request":"$Request","ProductFilter":"$ProductFilter","BreadCrumbs":"$BreadCrumbs","ShowCaseHtml":"$ShowCaseHtml"},"PageResult": {$push : "$PageResult"}
}}
)

How can i access N th level of Sub Document in MongoDB

{
"_id" : ObjectId("5b4d815ad85250f4e502d142"),
"company_Name" : "Rishabh Instruments",
"spaces" : [
{
"_id" : "11",
"name" : "Trishala",
"spaces" : [
{
"_id" : "111",
"name" : "ESL"
},
{
"_id" : "112",
"name" : "IS"
}
]
},
{
"_id" : "12",
"name" : "Riddhi",
"spaces" : [
{}
]
},
{
"name" : "XYZ",
"spaces" : [
{}
]
}
]
}
This is my Document structure in Mongo DB and it may have the sub documents upto N th level so for now I want to access the document named with ESL and IS. so how can i do that i am able to go upto 2nd level with below query so
db.space.aggregate([
{$match: {company_Name: 'Rishabh Instruments'}},
{$unwind: '$spaces'},
{$match: {'spaces.name': 'Trishala'}}
// {$unwind: '$spaces'},
// {$match: {'spaces.name': 'ESL'}}
])
but if i uncomment those two lines then it doesn't return any thing
so can anyone guide me or give any hint.
I tried the below solution and its working as expected i can go to N th level by chaining the key as in my case key is spaces
db.space.aggregate([
{$match: {company_Name: 'Rishabh Instruments'}},
{$unwind: '$spaces'},
{$match: {'spaces.name': 'Trishala'}},
{$unwind: '$spaces.spaces'},
{$match: {'spaces.spaces.name': 'ESL'}}
])
Try this aggregate query with projection to match the sample output you had provided :
db.space.aggregate([
{$match: {company_Name: 'Rishabh Instruments'}},
{$unwind: '$spaces'},
{$match: {'spaces.name': 'Trishala'}},
{$unwind: '$spaces.spaces'},
{$match: {$or : [{'spaces.spaces.name': 'ESL'},{'spaces.spaces.name': 'IS'}]}},
{$project : {_id : 0, _id :'$spaces.spaces._id', name:'$spaces.spaces.name'}}
])
Output :
{ "_id" : "111", "name" : "ESL" }
{ "_id" : "112", "name" : "IS" }

Mongodb - create ranking of values from field array

I am trying to sort a mongodb aggregate I don't what it is happening. I was searching some solution in stack overflow but they didn't work and I don't know why...
My idea is return a ranking of values from the field array (tags). I could achieve the list the sum of values but I can not sort it...
This is the query that I could do and it seems that it works:
db.getCollection("metadata").aggregate(
{$unwind: '$tags'},
{$group: {_id:'$tags.name', total: {$sum: 1}}}
);
Because I receive this result that It has sense:
{
"_id" : "kite",
"total" : 1.0
}
{
"_id" : "piggy bank",
"total" : 1.0
}
{
"_id" : "sorrel",
"total" : 1.0
}
{
"_id" : "eggnog"
"total" : 4.0
}
{
"_id" : "Weimaraner",
"total" : 1.0
}
{
"_id" : "bassinet",
"total" : 15.0
}
{
"_id" : "squirrel monkey",
"total" : 1.0
}
{
"_id" : "bath towel",
"total" : 6.0
}
TRIES
When I tried something like this:
db.getCollection("metadata").aggregate(
{$unwind: '$tags'},
{$group: {_id:'$tags.name', total: {$sum: 1}}},
{$sort: {total: -1}}
);
RESULT TRY:
{
"_id" : "baboon",
"total" : 12.0
}
{
"_id" : "snow leopard",
"total" : 4.0
}
{
"_id" : "green lizard",
"total" : 5.0
}
{
"_id" : "Dandie Dinmont",
"total" : 7.0
}
{
"_id" : "echidna",
"total" : 8.0
}
{
"_id" : "bee eater",
"total" : 6.0
}
or like this:
db.getCollection("metadata").aggregate(
{$unwind: '$tags'},
{$group: {_id: { name:'$tags.name', total: {$sum: 1}}}},
{$sort: {total: -1}}
);
The result doesn't sort or directly not sum the values...
EXTRA
This is the query if I want to list all the entries with the array:
db.getCollection('metadata').find({tags: {$exists: true}})
And the result is:
/* 2 */
{
"_id" : ObjectId("5900af3ff6844d2f7519fe13"),
"user_id" : 23,
"company_id" : 1,
"created" : ISODate("2017-04-26T14:31:27.000Z"),
"md5file" : "fdd30b1ca52e1c15f330f46c0079498c",
"path" : "/storage/emulated/0/DCIM/Camera/IMG_20160605_133703.jpg",
"image_width" : 3456,
"image_height" : 4608,
"originalTags" : [
{
"name" : "sleeping bag",
"percentage" : 0.7529412
},
{
"name" : "diaper",
"percentage" : 0.05490196
},
{
"name" : "bib",
"percentage" : 0.039215688
}
],
"tags" : [
{
"name" : "sleeping bag",
"percentage" : 0.7529412
}
]
}
/* 3 */
{
"_id" : ObjectId("5900af3ff6844d2f7519fe14"),
"user_id" : 23,
"company_id" : 1,
"created" : ISODate("2017-04-26T14:31:27.000Z"),
"md5file" : "22612c8bc99d1031146f7c9918555572",
"path" : "/storage/emulated/0/DCIM/Camera/IMG_20160605_164243.jpg",
"image_width" : 4608,
"image_height" : 3456,
"originalTags" : [
{
"name" : "bath towel",
"percentage" : 0.62352943
},
{
"name" : "quilt",
"percentage" : 0.101960786
},
{
"name" : "cradle",
"percentage" : 0.043137256
}
],
"tags" : [
{
"name" : "bath towel",
"percentage" : 0.62352943
}
]
}
Aggregation pipeline is an array. It should be wrapped in square brackets []:
db.getCollection("metadata").aggregate(
[
{$unwind: '$tags'},
{$group: {_id:'$tags.name', total: {$sum: 1}}},
{$sort: {total: -1}}
]
);

Get matched embedded document(s) from array

I've got a lot of documents using the following structure in MongoDB:
{
"_id" : ObjectId("..."),
"plant" : "XY_4711",
"hour" : 1473321600,
"units" : [
{
"_id" : ObjectId("..."),
"unit_id" : 10951,
"values" : [
{
"quarter" : 1473321600,
"value" : 395,
},
{
"quarter" : 1473322500,
"value" : 402,
},
{
"quarter" : 1473323400,
"value" : 406,
},
{
"quarter" : 1473324300,
"value" : 410,
}
]
}
]
}
Now I need to find all embedded document values where the quarter is between some given timestamps (eg: { $gte: 1473324300, $lte: 1473328800 }).
I've only got the unit_id and the quarter timestamp from/to for filtering the documents. And I only need the quarter and value grouped and ordered by unit.
I'm new in MongoDB and read something about find() and aggregate(). But I don't know how to do it. MongoDB 3.0 is installed on the server.
Finally I've got it:
I simply have to take apart each array, filtering out the things I don't need and put it back together:
db.collection.aggregate([
{$match : {$and : [{"units.values.quarter" : {$gte : 1473324300}}, {"units.values.quarter" : {$lte : 1473328800 }}]}},
{$unwind: "$units"},
{$unwind: "$units.values"},
{$match : {$and : [{"units.values.quarter" : {$gte : 1473324300}}, {"units.values.quarter" : {$lte : 1473328800 }}]}},
{$project: {"units": {values: {quarter: 1, "value": 1}, unit_id: 1}}},
{$group: {"_id": "$units.unit_id", "quarter_values": {$push: "$units.values"}}} ,
{$sort: {"_id": 1}}
])
Will give:
{
"_id" : 10951,
"quarter_values" : [
{
"quarter" : 1473324300,
"value" : 410
},
{
"quarter" : 1473325200,
"value" : 412
},
{
"quarter" : 1473326100,
"value" : 412
},
{
"quarter" : 1473327000,
"value" : 411
},
{
"quarter" : 1473327900,
"value" : 408
},
{
"quarter" : 1473328800,
"value" : 403
}
]
}
See: Return only matched sub-document elements within a nested array for a detailed description!
I think I have to switch to $map or $filter in the future. Thanks to notionquest for supporting my questions :)
Please see the sample query below. I didn't exactly get your grouping requirement. However, with this sample query you should be able to change and get your desired output.
db.collection.aggregate([
{$unwind : {path : "$units"}},
{$match : {$and : [{"units.values.quarter" : {$gte : 1473324300}}, {"units.values.quarter" : {$lte : 1473328800 }}]}},
{$project : {"units" : {values : {quarter : 1, "value" : 1}, unit_id : 1}}},
{$group : { _id : "$units.unit_id", quarter_values : { $push :{ quarter : "$units.values.quarter", value : "$units.values.value"}}}},
{$sort : {_id : 1 }}
]);
Sample output:-
{
"_id" : 10951,
"quarter_values" : [
{
"quarter" : [
1473321600,
1473322500,
1473323400,
1473324300
],
"value" : [
395,
402,
406,
410
]
}
]
}

MongoDB double $group aggregation

I have several documents that looks like this:
{
"_id" : ObjectId("50b59cd75bed76f46522c34e"),
"player_id" : 0,
"league_id" : 2,
"results" : [
{ "discipline" : "football",
"score" : 25.15
},
{
"discipline" : "basketball",
"score" : 21.24
},
{
"discipline" : "cycling",
"score" : 68.19
},]
}
I try to aggregate this data. First unwind results array, then leave only "football" and "cycling", next count average result. This part I did, and it is working.
My code:
db.grades.aggregate(
{$unwind:"$results"},
{$match: {$or: [{"results.discipline":"football"},{"results.discipline":"cycling"} ]}},
{$group:{_id:{player_id:"$player_id",league_id:"$league_id"}, 'average':{$avg:"$results.score"}}},
)
Then I try to aggregate by league_id, it means, average players results in specific leagues, add to code above:
{$group:{_id:"$_id.league_id",aver_league:{$avg:$average}}}
And now code looks like:
db.grades.aggregate(
{$unwind:"$results"},
{$match: {$or: [{"results.discipline":"football"},{"results.discipline":"cycling"} ]}},
{$group:{_id:{player_id:"$player_id",league_id:"$league_id"}, 'average':{$avg:"$results.score"}}},
{$group:{_id:"$_id.league_id",aver_league:{$avg:$average}}}
)
Console displays: JavaScript execution failed: ReferenceError: $average is not defined. What is wrong? Where did I make a mistake? Is it possible to aggregate by _id.league_id?
Try this pipeline:
[
{$unwind:"$results"},
{$match: {"results.discipline":{$in:["football", "basketball"]}}},
{$group{_id:{player_id:"$player_id",league_id:"$league_id"}, 'average':{$avg:"$results.score"}}}
]
it works for me with your doc:
{
"result" : [
{
"_id" : {
"player_id" : 0,
"league_id" : 2
},
"average" : 23.195
}
],
"ok" : 1
}
UPD. If you want to group again, by league_id:
[{$unwind:"$results"},
{$match: {"results.discipline":{$in:["football", "basketball"]}}},
{$group:{_id:{player_id:"$player_id",league_id:"$league_id"}, 'average':{$avg:"$results.score"} }},
{$group:{_id:"$_id.league_id", 'average':{$avg:"$average"} }} ]
{ "result" : [ { "_id" : 2, "average" : 23.195 } ], "ok" : 1 }