Grouping in MongoDB Aggregate - mongodb

I am starting with MongoDB and i find the Aggregate function hard to understand.
i have read many topics and tried many things, however i still don't get the results i am looking for.
I would like to group some things together to make a overview of the amount of things based on a few match parameters.
my DB:
{
"_id" : ObjectId("5943a4f015813165b6d2b79a"),
"productType" : "mail",
"productAmount" : 1,
"orderid" : "1497607274",
"location" : "99",
"sublocation" : "02",
"date" : ISODate("2017-01-01T09:01:13.000Z"),
"__v" : 0
}
/* 2 */
{
"_id" : ObjectId("5943a4f915813165b6d2b79c"),
"productType" : "mail",
"productAmount" : 1,
"orderid" : "1497607274",
"location" : "99",
"sublocation" : "01",
"date" : ISODate("2017-01-01T09:01:13.000Z"),
"__v" : 0
}
/* 3 */
{
"_id" : ObjectId("5943a4fe15813165b6d2b79e"),
"productType" : "mail",
"productAmount" : 1,
"orderid" : "1497607274",
"location" : "25",
"sublocation" : "01",
"date" : ISODate("2017-01-01T09:01:13.000Z"),
"__v" : 0
}
/* 4 */
{
"_id" : ObjectId("5943a56d15813165b6d2b7a0"),
"productType" : "mail",
"productAmount" : 1,
"orderid" : "1497607274",
"location" : "99",
"sublocation" : "01",
"date" : ISODate("2017-01-01T09:01:13.000Z"),
"__v" : 0
}
/* 5 */
{
"_id" : ObjectId("5943a971a367b069bb3e863c"),
"productType" : "mail",
"productAmount" : 1,
"orderid" : "1497607274",
"location" : "98",
"sublocation" : "01",
"date" : ISODate("2017-01-01T09:01:13.000Z"),
"__v" : 0
}
/* 6 */
{
"_id" : ObjectId("5943d824900fce1821c5845d"),
"productType" : "keychain",
"productAmount" : 1,
"orderid" : "1497607251",
"location" : "25",
"sublocation" : "01",
"date" : ISODate("2017-01-01T09:01:13.000Z")
}
/* 7 */
{
"_id" : ObjectId("5943d9ea900fce1821c5845e"),
"productType" : "mail",
"productAmount" : 1,
"orderid" : "1497607251",
"location" : "25",
"sublocation" : "02",
"date" : ISODate("2017-01-01T09:01:13.000Z")
}
my current query:
db.getCollection('products').aggregate([
{ $group: {
_id : {
"orderid" : "$orderid",
"location" : "$location",
"product" : "$productType",
"sublocation" : "$sublocation",
"date" : "$date",
"aant" : { "$sum" : "$productAmount"}
},
"aantal" : { "$sum" : 1},
"aantal2" : { "$sum" : "$productAmount"}
}
},
{
$group : {
_id : "$_id.product",
"productType" : {
"$push" : {
"loc" : "$_id.location",
"prodtype": "$_id.product",
"count": "$aantal2"},
},
"cnt": {"$sum" : "$aantal2"}
}
}
])
i would like to have this result:
{
Location: 25,
sublocation: 01,
<productTypeX> : <count the number of these products>,
<productTypeY> : <count the number of these products>,
<productTypeZ> : <count the number of these products>
},
{
Location: 25,
sublocation: 02,
<productTypeX> : <count the number of these products>,
<productTypeY> : <count the number of these products>,
<productTypeZ> : <count the number of these products>
}
or:
{
location: 25,
sublocation: 01,
products: [
{
<productTypeX> : <count>,
<productTypeY> : <count>,
<productTypeZ> : <count>
}
},
{
location: 25,
sublocation: 02
products: [
{
<productTypeX> : <count>,
<productTypeY> : <count>,
<productTypeZ> : <count>
}
}
if i get this to work i need to convert it to mongoose for NodeJS (tips are welcome)
Thanks in advance!

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"
}

Find element from document

i've passed a mysql database to mongoDB for a project. My db is about a pharmacy. I have a collection of factures, where which has the list of medicines sold. I'm trying to find the medicine which was sold the most.
{
"_id" : ObjectId("5c3c71f2760c4f47c701fe13"),
"cliente" : {
"tlmv" : "910987654",
"nome" : "Josefina Vivida da Paz",
"nif" : "122133144",
"pontos" : NumberLong(0),
"id" : NumberLong(2),
"pass" : "1eab06cab995dfeb32b6b7c709b8a6c62cabacfe",
"email" : "josefina#hotmail.pt"
},
"data_f" : ISODate("2018-06-03T00:00:01Z"),
"data_s" : ISODate("2018-06-02T23:55:59Z"),
"desconto" : 0,
"funcionario" : {
"tlmv" : "934567123",
"nome" : "Pedro Jorge Rito Lima",
"ordenado" : 800.32,
"iban" : "PT 50 2751 3262 76598707612",
"pass" : "3cfa1c281281ffe4f5db2ccfbe7a17f8a9479808",
"niss" : "14385639201",
"id" : NumberLong(2),
"cedula" : "54321"
},
"id" : NumberLong(15),
"id_c" : NumberLong(2),
"id_func" : NumberLong(2),
"medicamentos" : [
{
"categoria" : "Analg�sico",
"receita" : "N",
"des" : "Ben-U-Ron 500",
"qt" : 20,
"formato" : "granulado",
"qt_v" : NumberLong(1),
"pos" : "A12",
"lab" : "Laborat�rio do Rio Ave",
"preco_l" : 2.51,
"un" : "un",
"preco" : 2.51,
"preco_v" : 2.51,
"id" : NumberLong(1),
"stock" : NumberLong(21)
},
{
"categoria" : "Estatina",
"receita" : "S",
"des" : "Sinvastatina",
"qt" : 30,
"formato" : "comprimido",
"qt_v" : NumberLong(1),
"pos" : "K23",
"lab" : "Mylan",
"preco_l" : 16.45,
"un" : "un",
"preco" : 16.45,
"preco_v" : 16.45,
"id" : NumberLong(6),
"stock" : NumberLong(25)
}
],
"pontos_r" : NumberLong(10),
"pontos_u" : NumberLong(0),
"total" : 18.96
}
So my objective is to count every medicine -"medicamento"- sorted by different descriptions-"des". Similiar to Count on mysql. Any ideas how? The code above is abount 1 facture.
You need $unwind to get a medicine per document and then $group with $sum to get count per medicine, try:
db.collection.aggregate([
{
$unwind: "$medicamentos"
},
{
$group: {
_id: "$medicamentos.des",
count: { $sum: 1 }
}
}
])

mongoDb field count query

I have MongoDB collection with the following format:
{
"_id" : ObjectId("5b6b112d1bbd972848b97df4"),
"Game" : [
{
"City" : "Nizhny Novgorod",
"T2N" : "Costa Rica",
"T1N" : "Switzerland",
"ST" : "Nizhny Novgorod Stadium",
"T1S" : "2",
"Date" : "6/27/2018",
"T2S" : "2"
},
{
"City" : "Kaliningrad",
"T2N" : "Serbia",
"T1N" : "Switzerland",
"ST" : "Kaliningrad Stadium",
"T1S" : "2",
"Date" : "6/22/2018",
"T2S" : "1"
},
{
"City" : "Rostov-on-Don",
"T2N" : "Brazil",
"T1N" : "Switzerland",
"ST" : "Rostov Arena",
"T1S" : "1",
"Date" : "6/17/2018",
"T2S" : "1"
},
{
"City" : "Saint Petersburg",
"T2N" : "Sweden",
"T1N" : "Switzerland",
"ST" : "Saint Petersburg Stadium",
"T1S" : "0",
"Date" : "7/3/2018",
"T2S" : "1"
}
],
"team" : "Switzerland"
}
How can I get the total of T1S and Total of T2S for each team?
I am trying the following query
db.test3.aggregate([{$match:{}},{$group:{_id:"$team", goalScored:{$sum:"Game.T1S"},goalConceaded:{$sum:"Game.T2S"}}}])
But I am getting the following output:
{ "_id" : "Tunisia", "goalScored" : 0, "goalConceaded" : 0 }
{ "_id" : "Uruguay", "goalScored" : 0, "goalConceaded" : 0 }
{ "_id" : "Egypt", "goalScored" : 0, "goalConceaded" : 0 }
In the above, the goalscored and goalconceded are always 0 which is not expected. Any help is appreciated.

Need Help Join Collection

Collection Inventory sample data:
{
"_id" : "89011704252315531324",
"sku" : "A2015-01-000",
"type" : "package",
"status" : "active",
"lng" : "-72.789153",
"lat" : "44.173515",
"acq" : "28",
"gtime" : ISODate("2017-01-11T22:27:48.000Z"),
"qlng" : "-72.796501",
"qlat" : "44.214783",
"qtime" : ISODate("2016-11-27T18:21:10.000Z"),
"timestamp" : ISODate("2017-01-12T14:43:29.000Z"),
"modified" : Date(-62135596800000),
"battery" : "60",
"wearables" : [
{
"_id" : "0009003C100228234E45",
"type" : "wearable",
"status" : "active",
"battery" : "50",
"timestamp" : ISODate("2017-01-12T11:43:33.000Z")
},
{
"_id" : "004A003F200B36634E45",
"type" : "cradle",
"status" : "active",
"battery" : "64",
"timestamp" : ISODate("2017-01-11T22:27:26.000Z")
},
{
"_id" : "11223344556600000B55",
"type" : "falldetect",
"status" : "active",
"battery" : "64",
"timestamp" : ISODate("2017-01-12T08:43:29.000Z")
}
],
"company" : "ConnectAmericaProduction",
"companies" : [],
"remoteIp" : "172.31.45.196:53864",
"subscriber" : "5783e20aa2c89f346e000006",
"ring" : "90",
"speaker" : "90",
"mic" : "55",
"version" : "4352",
"cradle" : "OFF",
"ctime" : ISODate("2017-01-11T23:13:59.000Z"),
"csqtime" : Date(-62135596800000)
}
collection calllog sample data
{
"_id" : "89011704252315531324",
"cdr" : [
{
"direction" : "Outgoing",
"duration" : 46,
"timestamp" : ISODate("2016-11-23T03:25:06.000Z"),
"number" : "",
"name" : "Call Center",
"lng" : "-71.208061",
"lat" : "42.330265",
"acq" : "",
"timezone" : {
"dstOffset" : 0.0,
"rawOffset" : 0.0,
"status" : "",
"timeZoneId" : "",
"timeZoneName" : ""
}
},
{
"direction" : "Incoming",
"duration" : 51,
"timestamp" : ISODate("2016-11-23T03:26:02.000Z"),
"number" : "",
"name" : "Call Center",
"lng" : "-71.205727",
"lat" : "42.333347",
"acq" : "",
"timezone" : {
"dstOffset" : 0.0,
"rawOffset" : 0.0,
"status" : "",
"timeZoneId" : "",
"timeZoneName" : ""
}
},
{
"direction" : "Outgoing",
"duration" : 49,
"timestamp" : ISODate("2016-11-27T18:21:04.000Z"),
"number" : "",
"name" : "Call Center",
"lng" : "-72.796501",
"lat" : "44.214783",
"acq" : "",
"timezone" : {
"dstOffset" : 0.0,
"rawOffset" : -18000.0,
"status" : "OK",
"timeZoneId" : "America/New_York",
"timeZoneName" : "Eastern Standard Time"
}
}
]
}
after run this aggrgrate function
db.calllog.aggregate([{$unwind: "$cdr"}, {$lookup:{from: "inventory", localField: "_id", foreignField: "_id", as: "wearables" }}, { "$project": { "cdr.direction": 1, "cdr.duration": 1,"cdr.date": 1,"wearables.type": 1, "wearables.status": 1, "wearables.battery": 1} }])
Result:
{ "_id" : "89011704252315531324", "cdr" : { "direction" : "Outgoing", "duration" : 46 }, "wearables" : [ { "type" : "package", "status" : "active", "battery" : "60" } ] }
{ "_id" : "89011704252315531324", "cdr" : { "direction" : "Incoming", "duration" : 51 }, "wearables" : [ { "type" : "package", "status" : "active", "battery" : "60" } ] }
{ "_id" : "89011704252315531324", "cdr" : { "direction" : "Outgoing", "duration" : 49 }, "wearables" : [ { "type" : "package", "status" : "active", "battery" : "60" } ] }
needed help can not get query to shows wearables type such as wearable, cradle, falldetect
thank
Did you try to do wearables.wearables.type? When you call wearables.type, you are actually getting the type of the Inventory. If you need the type of the wearable that is inside the inventory. You need to put inventory.wearables.type. The initial problem is that you're calling the inventory "wearables" and making a confusion out of it.
I would do the following:
db.calllog.aggregate([{$unwind: "$cdr"},
{$lookup:{from: "inventory", localField: "_id", foreignField: "_id", as: "inventory" }},
{$unwind: "$inventory.wearables"},
{ "$project": {
"cdr.direction": 1,
"cdr.duration": 1,
"cdr.date": 1,
"inventory.type": 1,
"inventory.status": 1,
"inventory.battery": 1,
"inventory.wearables.type":1
}}])

How to query in mongodb to get distinct record with count

I have collection who's name is transactions.
I'm sharing the object of transactions collection
{
"_id" : ObjectId("58aaec83f1dc6914082afe31"),
"amount" : "33.00",
"coordinates" : {
"lat" : "4.8168",
"lon" : "36.4909"
},
"cuisine" : "Mexican",
"date" : ISODate("0062-02-22T11:46:52.738+05:30"),
"location" : {
"address" : "2414 Trudie Rue",
"city" : "West Alisa",
"state" : "New York",
"zip" : "10000"
},
"place_name" : "Outdoors",
"place_type" : "Wooden"
},
{
"_id" : ObjectId("58aaec83f1dc6914082afe32"),
"amount" : "557.00",
"coordinates" : {
"lat" : "-36.6784",
"lon" : "131.3698"
},
"cuisine" : "Australian",
"date" : ISODate("1294-10-04T19:53:15.562+05:30"),
"location" : {
"address" : "5084 Buckridge Cove",
"city" : "Sylviaview",
"state" : "Hawaii",
"zip" : "51416-6918"
},
"place_name" : "Toys",
"place_type" : "Cotton"
},
{
"_id" : ObjectId("58aaec83f1dc6914082afe33"),
"amount" : "339.00",
"coordinates" : {
"lat" : "45.1468",
"lon" : "91.4097"
},
"cuisine" : "Mexican",
"date" : ISODate("1568-11-25T02:54:53.046+05:30"),
"location" : {
"address" : "94614 Harry Island",
"city" : "Cartwrightside",
"state" : "Louisiana",
"zip" : "18825"
},
"place_name" : "Clothing",
"place_type" : "Frozen"
},
{
"_id" : ObjectId("58aaec83f1dc6914082afe34"),
"amount" : "173.00",
"coordinates" : {
"lat" : "-57.2738",
"lon" : "19.6381"
},
"cuisine" : "Australian",
"date" : ISODate("0804-05-07T03:00:07.724+05:30"),
"location" : {
"address" : "1933 Lewis Street",
"city" : "Aufderharville",
"state" : "Louisiana",
"zip" : "23416"
},
"place_name" : "Beauty",
"place_type" : "Fresh"
},
{
"_id" : ObjectId("58aaec83f1dc6914082afe34"),
"amount" : "173.00",
"coordinates" : {
"lat" : "-57.2738",
"lon" : "19.6381"
},
"cuisine" : "Australian",
"date" : ISODate("0804-05-07T03:00:07.724+05:30"),
"location" : {
"address" : "1933 Lewis Street",
"city" : "Aufderharville",
"state" : "Louisiana",
"zip" : "23416"
},
"place_name" : "Beauty",
"place_type" : "Fresh"
}
I want to get the list of distinct cuisine with total count
Output
{
"name" : 'Mexican',
"count" : '2'
},
{
"name" : 'Australian',
"count" : '3'
},
I could have done easily with mysql but I dot know in mongodb as I'm new with mongodb
I have tried with the example and I found nothing:
db.transactions.aggregate(
{$group: {_id:'$cuisine'},count:{$sum:1}}
).result;
Please try the code below. You should group by cuisine the records and get the count of them. Later in project pipeline you can define the final look.
db.transactions.aggregate([
{ $group: { _id: "$cuisine", count: { $sum: 1 } } },
{ $project:{ _id: 0, name: "$_id", count:"$count" } }
]);