Mongodb aggregate match value in array - mongodb

i'm working with the restaurants db in mongo
{
"_id" : ObjectId("5c66fcf59e184ea712adfba6"),
"address" : {
"building" : "97-22",
"coord" : [
-73.8601152,
40.7311739
],
"street" : "63 Road",
"zipcode" : "11374"
},
"borough" : "Queens",
"cuisine" : "Jewish/Kosher",
"grades" : [
{
"date" : ISODate("2014-11-24T00:00:00.000Z"),
"grade" : "Z",
"score" : 20
},
{
"date" : ISODate("2013-01-17T00:00:00.000Z"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2012-08-02T00:00:00.000Z"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2011-12-15T00:00:00.000Z"),
"grade" : "B",
"score" : 25
}
],
"name" : "Tov Kosher Kitchen",
"restaurant_id" : "40356068"
}
I'm tryng to filter with match in aggregate. I want to check if any score in grades is greater than 5
db.runCommand({
aggregate: "restaurants",
pipeline : [
{$match: {"grades": {$anyElementTrue: {"score": {$gt:5}}}}}
but i'm getting this error:
"errmsg" : "unknown operator: $anyElementTrue",
thanks

Try with $eleMatch
db.restaurants.aggregate([{$match: {"grades": {$elemMatch: {"score": {$gt:5}}}}}])

Related

Map/reduce mongodb using two attributes

I'm practicing with mongo using the sample db restaurants.
The db has the following structure:
{
"_id" : ObjectId("6035397d0076410d79b29bde"),
"address" : {
"building" : "522",
"coord" : [
-73.95171,
40.767461
],
"street" : "East 74 Street",
"zipcode" : "10021"
},
"borough" : "Manhattan",
"cuisine" : "American ",
"grades" : [
{
"date" : ISODate("2014-09-02T00:00:00Z"),
"grade" : "A",
"score" : 12
},
{
"date" : ISODate("2013-12-19T00:00:00Z"),
"grade" : "B",
"score" : 16
},
{
"date" : ISODate("2013-05-28T00:00:00Z"),
"grade" : "A",
"score" : 9
},
{
"date" : ISODate("2012-12-07T00:00:00Z"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2012-03-29T00:00:00Z"),
"grade" : "A",
"score" : 11
}
],
"name" : "Glorious Food",
"restaurant_id" : "40361521"
}
{
"_id" : ObjectId("6035397d0076410d79b29bdf"),
"address" : {
"building" : "284",
"coord" : [
-73.9829239,
40.6580753
],
"street" : "Prospect Park West",
"zipcode" : "11215"
},
"borough" : "Brooklyn",
"cuisine" : "American ",
"grades" : [
{
"date" : ISODate("2014-11-19T00:00:00Z"),
"grade" : "A",
"score" : 11
},
{
"date" : ISODate("2013-11-14T00:00:00Z"),
"grade" : "A",
"score" : 2
},
{
"date" : ISODate("2012-12-05T00:00:00Z"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2012-05-17T00:00:00Z"),
"grade" : "A",
"score" : 11
}
],
"name" : "The Movable Feast",
"restaurant_id" : "40361606"
}
What I'm trying to do is to get the total of cuisines per borought. So, if a borought has 5 resturants, but in this restaurants, 2 serve the same kind of food, my total should be 4.
I'm suposed to use map/reduce/finalize functions, but I can't figure out how.
All exemples I saw, in the map you have just one attribute to filter de data, but I need to group the restaurants of the same borough and then group e count by cuisine.
Can anyone help me? I've been tryng for a long time, didn't get enyware. The best I manage was to count the total of restaurants per borough.
Thank you.
Try this:
db.restaurants.aggregate([
// First group by "borough" and "cousine".
{
$group: {
_id: {
"borough": "$borough",
"cuisine": "$cuisine"
},
count: { $first: 1 }
}
},
// Second group by only "borough".
{
$group: {
_id: "$_id.borough",
count: { $sum: "$count" }
}
}
]);
Output:
/* 1 */
{
"_id" : "Brooklyn",
"count" : 1
},
/* 2 */
{
"_id" : "Manhattan",
"count" : 2
}
My test data:
/* 1 createdAt:2/24/2021, 11:35:10 PM*/
{
"_id" : ObjectId("6036955624f3423874ac9540"),
"borough" : "Manhattan",
"cuisine" : "Indian",
"restaurant_id" : "40361605"
},
/* 2 createdAt:2/24/2021, 11:35:10 PM*/
{
"_id" : ObjectId("6036955624f3423874ac953f"),
"borough" : "Brooklyn",
"cuisine" : "American",
"restaurant_id" : "40361606"
},
/* 3 createdAt:2/24/2021, 11:35:10 PM*/
{
"_id" : ObjectId("6036955624f3423874ac953e"),
"borough" : "Manhattan",
"cuisine" : "American",
"restaurant_id" : "40361522"
},
/* 4 createdAt:2/24/2021, 11:35:10 PM*/
{
"_id" : ObjectId("6036955624f3423874ac953d"),
"borough" : "Manhattan",
"cuisine" : "American",
"restaurant_id" : "40361521"
}

Aggregate distinct values in MongoDB

I have a mongodb db with 18625 collections. It has following keys:
"_id" : ObjectId("5aab14d2fc08b46adb79d99c"),
"game_id" : NumberInt(4),
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Sports",
"editors_choice" : "N",
"release_year" : NumberInt(2012),
"release_month" : NumberInt(9),
"release_day" : NumberInt(11)
Now, i wish to create another dimension/ collection with only genres.
If i use the following query :
db.ign.aggregate([ {$project: {"genre":1}}, { $out: "dimen_genre" } ]);
It generates 18625 collections, even though there are only 113 distinct
genres.
How to apply distinct here and get the collection for genres with only the distinct 113 values.
I googled, bt it showed that aggregate and distinct don't work together in mongo.
I also tried : db.dimen_genre.distinct('genre').length
this showed that in dimension_genre, there are 113 distinct genres.
Precisely,
how to make a collection from existing one with only distinct values.
I am really new to NoSQLs.
You can use $addToSet to group unique values in one document and then $unwind to get back multiple docs:
db.ign.aggregate([
{
$group: {
_id: null,
genre: { $addToSet: "$genre" }
}
},
{
$unwind: "$genre"
},
{
$project: {
_id: 0
}
},
{ $out: "dimen_genre" }
]);
You can try
db.names.aggregate(
[
{ $group : { _id : "$genre", books: { $push: "$$ROOT" } } }
]
)
I have tried with Test and Sports as genre
It gives you output something like this
{
"_id" : "Test",
"books" : [
{
"_id" : ObjectId("5aaea6150cc1403ee9a02e0c"),
"game_id" : 4,
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Test",
"editors_choice" : "N",
"release_year" : 2012,
"release_month" : 9,
"release_day" : 11
}
]
}
/* 2 */
{
"_id" : "Sports",
"books" : [
{
"_id" : ObjectId("5aaea3be0cc1403ee9a02d97"),
"game_id" : 4,
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Sports",
"editors_choice" : "N",
"release_year" : 2012,
"release_month" : 9,
"release_day" : 11
},
{
"_id" : ObjectId("5aaea3c80cc1403ee9a02d9b"),
"game_id" : 4,
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Sports",
"editors_choice" : "N",
"release_year" : 2012,
"release_month" : 9,
"release_day" : 11
},
{
"_id" : ObjectId("5aaea3cf0cc1403ee9a02d9f"),
"game_id" : 4,
"score_phrase" : "Great",
"title" : "NHL 13",
"url" : "/games/nhl-13/ps3-128181",
"platform" : "PlayStation 3",
"score" : 8.5,
"genre" : "Sports",
"editors_choice" : "N",
"release_year" : 2012,
"release_month" : 9,
"release_day" : 11
}
]
}

How to query mongodb with embedded document

Hi i'm practicing mongodb and I'm stuck with a problem. I'av the following set of documents.
{
"_id" : ObjectId("57cf9a134607674792dbad9e"),
"address" : {
"building" : "351",
"coord" : [
-73.9851356,
40.7676919
],
"street" : "West 57 Street",
"zipcode" : "10019"
},
"borough" : "Manhattan",
"cuisine" : "Irish",
"grades" : [
{
"date" : ISODate("2014-09-06T00:00:00.000Z"),
"grade" : "A",
"score" : 2
},
{
"date" : ISODate("2013-07-22T00:00:00.000Z"),
"grade" : "A",
"score" : 11
},
{
"date" : ISODate("2012-07-31T00:00:00.000Z"),
"grade" : "A",
"score" : 12
},
{
"date" : ISODate("2011-12-29T00:00:00.000Z"),
"grade" : "A",
"score" : 12
}
],
"name" : "Dj Reynolds Pub And Restaurant",
"restaurant_id" : "30191841"
}
I want to fetch list of all documents where zipcode is 10019
I'm following mongodb db tutorials and i've tried the following queries but nothing seems to work and i'm getting zero errors.
db.restaurants.find({address:{zipcode:10019}});
db.restaurants.find({"address.zipcode":10019})
zipcode is a string so your query should be
db.restaurants.find({ "address.zipcode": "10019" })
instead of
db.restaurants.find({ "address.zipcode": 10019 })

Simple update not working using positional $ operator

I'm just starting out with Mongo, and following the documentation here, I can't seem to update a value in a nested array when I apply the same technique.
This is my document:
{
"_id" : ObjectId("56d2cf8ee2b075667d4f0545"),
"address" : {
"building" : "522",
"coord" : [
-73.95171,
40.767461
],
"street" : "East 74 Street",
"zipcode" : "10021"
},
"borough" : "Manhattan",
"cuisine" : "American ",
"grades" : [
{
"date" : ISODate("2014-09-02T00:00:00Z"),
"grade" : "A",
"score" : 12
},
{
"grade" : "B",
"score" : 16,
"date" : ISODate("2013-12-19T00:00:00Z")
},
{
"date" : ISODate("2013-05-28T00:00:00Z"),
"grade" : "A",
"score" : 9
},
{
"date" : ISODate("2012-12-07T00:00:00Z"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2012-03-29T00:00:00Z"),
"grade" : "A",
"score" : 11
}
],
"name" : "Glorious Food",
"restaurant_id" : "40361521"
}
and this is my query:
db.restaurants.update(
{
_id: 'ObjectId("56d2cf8ee2b075667d4f0545")',
'grades.date': 'ISODate("2014-09-02T00:00:00Z")'
},
{
$set: { 'grades.$.score': 1 }
}
)
I'm sure I must have missed something obvious.
remove quotes from objectId and date field - please see below:
db.restaurants.update(
{
_id: ObjectId("56d2cf8ee2b075667d4f0545"),
"grades.date": ISODate("2014-09-02T00:00:00Z")
},
{
$set: { 'grades.$.score': 1 }
}
)

Exact Reduce function

I have a collection of the type :
{
"_id" : ObjectId("51f1fcc08188d3117c6da351"),
"cust_id" : "abc123",
"ord_date" : ISODate("2012-10-03T18:30:00Z"),
"status" : "A",
"price" : 25,
"items" : [{
"sku" : "ggg",
"qty" : 7,
"price" : 2.5
}, {
"sku" : "ppp",
"qty" : 5,
"price" : 2.5
}]
}
I want to fetch only the "items" object whose "items.qty">5 and and"items.sku"=="ggg".
I applied Map reduce:
cmd { "mapreduce" : "orders" , "map" : "function map(){var items_out={items:[]};for(i in this.items){items_out.items.push(this.items[i].sku);};emit(this._id,[items_out]);}" , "reduce" : "function reduce(key,values){return {'result':values};}" , "verbose" : true , "out" : { "replace" : "map_reduce"} , "query" : { "$where" : "return this.items.some(function(entry){return entry.qty>5})&&this.items.some(function(entry){return entry.sku=='ggg'})"}},
but I am getting all the sku values something like this:
{ "data": [ { "items": [ "ggg", "ppp" ] } ]}
Whereas it should give only ggg as this is the only value matching criteria.
Use the following command:
db.orders.aggregate(
{$unwind : "$items"},
{$match : {"items.qty": {$gt: 5 }}},
{$match : {"items.sku" : "ggg"}},
{$project : {_id:0, items:1}}
)