I have a collection that contains data as below sample
{ "_id" : "...." , "team" : [ {"name" : "A", "state" : "Active"} , {"name" : "B", "state" : "Deactive", {"name" : "C", "state" : "Unknown"} } ]},
{ "_id" : "...." , "team" : [ {"name" : "A", "state" : "Unknown"} , {"name" : "B", "state" : "Deactive", {"name" : "C", "state" : "Unknown"} } ]},
{ "_id" : "...." , "team" : [ {"name" : "A", "state" : "Active"} , {"name" : "B", "state" : "Deactive", {"name" : "C", "state" : "Unknown"} } ]}
I filter by "team.name" and want to know what is state and count each state as below sample result
{ "name" : "A", "Active" : 2, "Unknown" : 1},
{ "name" : "B", "Deactive" : 3},
{ "name" : "C", "Unknown" : 3"}
Is it possible to use only aggregate function of MongoDB without any codes?
Is it possible to use only aggregate function of MongoDB without any
codes?
Yes
TL;DR unwind and group
db.getCollection('foo').aggregate([
{$unwind:"$team"},
{
$group: {
_id: "$team.name",
"Active": {$sum: {$cond:[{$eq:["$team.state","Active"]},1,0]}},
"Deactive": {$sum: {$cond:[{$eq:["$team.state","Deactive"]},1,0]}},
"Unknown": {$sum: {$cond:[{$eq:["$team.state","Unknown"]},1,0]}}
}
},
{$project: {_id:0, name:"$_id", Active:1, Deactive:1, Unknown:1}},
{$sort: {name:1}}
])
Output for your sample:
[
{ "name" : "A", "Active" : 2, "Deactive" : 0, "Unknown" : 1 },
{ "name" : "B", "Active" : 0, "Deactive" : 3, "Unknown" : 0 },
{ "name" : "C", "Active" : 0, "Deactive" : 0, "Unknown" : 3 }
]
Related
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}}}}}])
I have following data:
{ "id" : 1, "lsPairs" :[{"location" : "L0", "service" : "S0" }]}
{ "id" : 2, "lsPairs" :[{"location" : "L0", "service" : "S0" },{"location" : "L1", "service" : "S1"}]}
{ "id" : 3, "lsPairs" :[{"location" : "L0", "service" : "S0" },{"location" : "L1", "service" : "S1"}, {"location" : "L2", "service" : "S2"}]}
{ "id" : 4, "lsPairs" :[{"location" : "L0", "service" : "S0" },{"location" : "L1", "service" : "S1"},{"location" : "L2", "service" : "S2"}, {"location" : "L3", "service" : "S3"}]}`
I want to get location count, service count and (location,service) pair count
{ "_id" : "L3" , "count" : 1}
{ "_id" : "L2" , "count" : 2}
{ "_id" : "L1" , "count" : 3}
{ "_id" : "L0" , "count" : 4}
{ "_id" : "S3" , "count" : 1}
{ "_id" : "S2" , "count" : 2}
{ "_id" : "S1" , "count" : 3}
{ "_id" : "S0" , "count" : 4}
{ "_id" : { "loc" : "L2" , "srv" : "S2"} , "count" : 2}
{ "_id" : { "loc" : "L1" , "srv" : "S1"} , "count" : 3}
{ "_id" : { "loc" : "L3" , "srv" : "S3"} , "count" : 1}
{ "_id" : { "loc" : "L0" , "srv" : "S0"} , "count" : 4}`
Now I run group function three times, group different id.
Any idea for using one group to get these result?
You will need to deconstruct the array with $unwind then $group the documents.
collection.aggregate([
{ $unwind: "$lsPairs" },
{ $group: {
_id: {
"loc": "$lsPairs.location",
"srv": "$lsPairs.service"
},
"count": { $sum: 1 }
}}
])
Output
{ "_id" : { "loc" : "L3", "srv" : "S3" }, "count" : 1 }
{ "_id" : { "loc" : "L2", "srv" : "S2" }, "count" : 2 }
{ "_id" : { "loc" : "L1", "srv" : "S1" }, "count" : 3 }
{ "_id" : { "loc" : "L0", "srv" : "S0" }, "count" : 4 }
Keep the first round location-service pair to a collection and reused it.
db.locservice.aggregate([ {$unwind:"$lsPairs"},
{$group:{_id:"$lsPairs",count: { $sum: 1}}},
{$sort:{_id:1}},
{$out:"lsp"} ])
Take location from temp collection and group it.
db.lsp.aggregate([{$project:{_id:0, loc:"$_id.location", count:1}},
{$group:{_id:"$loc", cnt:{$sum:"$count"}}}, {$sort:{_id:1}} ])
Take service from temp collection and group it.
db.lsp.aggregate([{$project:{_id:0, srv:"$_id.service", count:1}},
{$group:{_id:"$srv", cnt:{$sum:"$count"}}}, {$sort:{_id:1}} ])
The following I add location and service to array, can I group two array same time
db.locservice.aggregate([ {$unwind:"$lsPairs"},
{$group:{_id:"$lsPairs",count: { $sum: 1},
locs:{$push:{item:"$lsPairs.location"}},
srvs:{$push:{item:"$lsPairs.service"}}}},
{$project:{count:1, locs:1, srvs:1}} ])
{ "_id" : { "location" : "L3", "service" : "S3" }, "count" : 1, "locs" : [ { "item" : "L3" } ], "srvs" : [ { "item" : "S3" } ] }
{ "_id" : { "location" : "L2", "service" : "S2" }, "count" : 2, "locs" : [ { "item" : "L2" }, { "item" : "L2" } ], "srvs" : [ { "item" : "S2" }, { "item" : "S2" } ] }
{ "_id" : { "location" : "L1", "service" : "S1" }, "count" : 3, "locs" : [ { "item" : "L1" }, { "item" : "L1" }, { "item" : "L1" } ], "srvs" : [ { "item" : "S1" }, { "item" : "S1" }, { "item" : "S1" } ] }
{ "_id" : { "location" : "L0", "service" : "S0" }, "count" : 4, "locs" : [ { "item" : "L0" }, { "item" : "L0" }, { "item" : "L0" }, { "item" : "L0" } ], "srvs" : [ { "item" : "S0" }, { "item" : "S0" }, { "item" : "S0" }, { "item" : "S0" } ] }
I m actually facing a problem with mongoDB.
I need to display some statistics :
- A treatment is an information that contain a date, the user who treated, a list of anomalies
Can you help me with the request to get :
"The numbers of anomalies by users ?"
Thanks for all :D
db.treatment.aggregate(
{
$group : {_id : "$anomalies", totalUser : { $sum : 1 }}
}
);
Note : change your collection and document key name if I put wrong.
Source : http://www.mkyong.com/mongodb/mongodb-aggregate-and-group-example/
So, if your collection had the following documents:
> db.treatments.find()
{ "_id" : 1, "date" : ISODate("2014-08-29T15:44:45.843Z"), "user" : "A", "anomalies" : [ "a", "b", "c" ] }
{ "_id" : 2, "date" : ISODate("2014-08-29T15:45:01.782Z"), "user" : "A", "anomalies" : [ "e", "f", "g" ] }
{ "_id" : 3, "date" : ISODate("2014-08-29T15:45:34.889Z"), "user" : "B", "anomalies" : [ "a", "b", "c", "e", "f", "g" ] }
{ "_id" : 4, "date" : ISODate("2014-08-29T15:48:01.860Z"), "user" : "B", "anomalies" : [ "a", "b", "c", "e", "f", "g" ] }
{ "_id" : 5, "date" : ISODate("2014-08-29T15:48:28.937Z"), "user" : "A", "anomalies" : [ "x", "y", "z" ] }
You can use $group stage to $sum the $size of the anomalies array
> db.treatments.aggregate([ { $group: { _id: "$user", allAnomalies: { $sum: { $size: "$anomalies" } } } } ] )
{ "_id" : "B", "allAnomalies" : 12 }
{ "_id" : "A", "allAnomalies" : 9 }
I have document sales
db.sale.findOne({_id : ObjectId("52ea4dd29dbc7923107ddb97")})
{
"_id" : ObjectId("52ea4dd29dbc7923107ddb97"),
"firm" : ObjectId("52e56c009dbc794999ea5c3d"),
"patient" : {
"last" : "",
"first" : ""
},
"doc" : "",
"hospital" : "",
"discount" : 0,
"dd" : "",
"mode" : "cash",
"invoice" : "300114-undefined-1",
"items" : [
{
"bat" : "BJFE",
"narco" : 0,
"name" : "GDRNCCD",
"mrp" : 1,
"free" : 0,
"qty" : 1,
"item_discount" : 0,
"wpr" : 1,
"exp" : "1425168000000"
},
{
"bat" : "",
"narco" : 0,
"name" : "GDRN vbhjdsfb",
"mrp" : 1,
"free" : 0,
"qty" : 1,
"item_discount" : 0,
"wpr" : 0,
"exp" : "[object Object]"
},
{
"bat" : "",
"narco" : 0,
"name" : "GDRN vbhjdsfb",
"mrp" : 1,
"free" : 0,
"qty" : 1,
"item_discount" : 0,
"wpr" : 0,
"exp" : "[object Object]"
}
],
"date" : ISODate("2014-01-30T00:00:00Z"),
"mob" : "",
"email" : ""
}
How can I Aggregate total numbers if items in one field and sum up mrp *qty of all the items into one field.
I have read the mognodb aggregation but it only aggregates among group of matched documents not inside a single document. Is it possile?
{
"_id" : ObjectId("52ea4dd29dbc7923107ddb97"),
"firm" : ObjectId("52e56c009dbc794999ea5c3d"),
'total_items' : items.length,
"total" : mrp*qty of all items,
}
db.sales.aggregate(
{$unwind: "$items"},
{$project: {_id: 1,firm:1, total: {$multiply: ["$items.mrp", "$items.qty"]}}},
{$group: {_id: {"id":"$_id", firm:"$firm"}, count: {$sum:1} , total : {$sum:"$total"}}}
)
With a slight change : _id contains id and firm, you will need an extra projection to match your desired document, but I don't think it's important.
Plus, you can easily change to group by farm only
Thanks to Orid,I tried this,
db.sale.aggregate(
{ $match :{ firm :ObjectId("52e56c009dbc794999ea5c3d") } },
{$project : {day : {$dayOfMonth : '$date'},items :1,patient :1,invoice :1}},
{$match : {day: {$gte : new Date().getDate()}}},
{$unwind : "$items"},
{$project: {_id: 1,patient:1,invoice :1, total: {$multiply: ["$items.mrp", "$items.qty"]}}},
{$group: {_id: {"id":"$_id", invoice:"$invoice",patient :"$patient"}, count: {$sum:1} , total : {$sum:"$total"}}})
Result
{
"result" : [
{
"_id" : {
"id" : ObjectId("52eab6129dbc7923107ddbaf"),
"invoice" : "310114-undefined-1",
"patient" : {
"last" : "",
"first" : ""
}
},
"count" : 2,
"total" : 25
},
{
"_id" : {
"id" : ObjectId("52eab6129dbc7923107ddbb0"),
"invoice" : "310114-undefined-1",
"patient" : {
"last" : "",
"first" : ""
}
},
"count" : 1,
"total" : 1
},
{
"_id" : {
"id" : ObjectId("52eab6129dbc7923107ddbae"),
"invoice" : "310114-undefined-1",
"patient" : {
"last" : "",
"first" : ""
}
},
"count" : 2,
"total" : 5
}
],
"ok" : 1
}
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}}
)