MongoDB Use $group for the subset after $group - mongodb

I just learned mongoDB, I am trying to find some repeat customer info through my customer database.
The sample collection:
{
"_id" : ObjectId("5b7617e48146d8bae"),
"amazon_id" : "112",
"date" : "2018-01-25T18:40:55-08:00",
"email" : "xxxxx#marketplace.amazon.com",
"buy_name" : "xxxxx",
"sku" : "NPC-50",
"qty" : 8,
"price" : 215.92,
"reci_name" : "XXXXX",
"street1" : "XXXXX",
"street2" : "",
"street3" : "",
"city" : "XXXXX",
"state" : "XXXXX",
"zip_code" : "XXXXXX"
}
{
"_id" : ObjectId("5b761712e48146d8bae"),
"amazon_id" : "114",
"date" : "2018-01-27T18:40:55-08:00",
"email" : "xxxxx#marketplace.amazon.com",
"buy_name" : "xxxxx",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99,
"reci_name" : "XXXXX",
"street1" : "XXXXX",
"street2" : "",
"street3" : "",
"city" : "XXXXX",
"state" : "XXXXX",
"zip_code" : "XXXXXX"
}
I group all customer info by their email id, and here is my code:
db.getCollection('order').aggregate([
{ $group: { _id: "$email",
OrderInfo: {$push: {orderId: "$amazon_id", sku: "$sku", qty: "$qty", price:"$price"
}},
CustomerInfo: {$addToSet: {buyName: "$buy_name",reName: "$reci_name", email: "$email", street1: "$street1",
street2: "$street2", city: "$city", state: "$state", zipCode: "$zip_code"} }
}},
{ $project: {_id: 1, OrderInfo: 1, CustomerInfo:1, total_price:{$sum: "$OrderInfo.price"} }},
{ $match: {total_price: {$gt:100} } },
{ $sort: {total_price:-1}},
], { allowDiskUse: true } );
It shows me the result:
{
"_id" : "xxxxxxx#marketplace.amazon.com",
"OrderInfo" : [
{
"orderId" : "112",
"sku" : "NPC-50",
"qty" : 8,
"price" : 215.92
},
{
"orderId" : "112",
"sku" : "NPC-50",
"qty" : 1,
"price" : 26.99
},
{
"orderId" : "114",
"sku" : "NPC-50",
"qty" : 1,
"price" : 26.99
},
{
"orderId" : "114",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99
},
{
"orderId" : "116",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99
},
],
"CustomerInfo" : [
{
"buyName" : "xxxxxxxxx",
"reName" : "xxxxxxxxxxxx",
"email" : "xxxxxxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxxxxxxx",
"state" : "xxxxxxxxxxxx",
"zipCode" : "xxxxxxxxxx"
},
{
"buyName" : "xxxxxxxxxx",
"reName" : "xxxxxx",
"email" : "xxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxx",
"state" : "xxxx",
"zipCode" : "xxxxxxxx"
}
],
"total_price" : 309.88
}
However, I want to group the sku and sum up the qty and price in the OrderInfo Set. My expected output is something like:
{
"OrderInfo" : [
{
"sku": "NPC-50",
"qty": 10,
"price": 269.9
},
{
"sku": "ABC",
"qty": 2,
"price": 39.98
},
],
"CustomerInfo" : [
{
"buyName" : "xxxxxxxxx",
"reName" : "xxxxxxxxxxxx",
"email" : "xxxxxxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxxxxxxx",
"state" : "xxxxxxxxxxxx",
"zipCode" : "xxxxxxxxxx"
},
{
"buyName" : "xxxxxxxxxx",
"reName" : "xxxxxx",
"email" : "xxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxx",
"state" : "xxxx",
"zipCode" : "xxxxxxxx"
}
],
"total_price" : 309.88
}
Any Help will be appreciated.

You can use below aggregation.
db.order.aggregate([
{"$group":{
"_id":{"email":"$email","sku":"$sku"},
"qty":{"$sum":"$qty"},
"price":{"$sum":"$price"},
"CustomerInfo":{
"$addToSet":{
"buyName":"$buy_name",
"reName":"$reci_name",
"email":"$email",
"street1":"$street1",
"street2":"$street2",
"city":"$city",
"state":"$state",
"zipCode":"$zip_code"
}
}
}},
{"$group":{
"_id":"$_id.email",
"OrderInfo":{"$push":{"sku":"$_id.sku","qty":"$qty","price":"$price"}},
"total_price":{"$sum":"$price"},
"CustomerInfo":{"$first":"$CustomerInfo"}
}},
{"$match":{"total_price":{"$gt":100}}},
{"$sort":{"total_price":-1}}
])

You can try below aggregation
db.collection.aggregate([
{ "$group": {
"_id": {
"email": "$email",
"sku": "$sku"
},
"CustomerInfo": {
"$addToSet": {
"buyName": "$buy_name",
"otherFields": "$otherFields",
}
},
"price": { "$sum": "$price" },
"qty": { "$sum": "$qty" }
}},
{ "$group": {
"_id": "$_id.email",
"CustomerInfo": { "$first": "$CustomerInfo" },
"OrderInfo": {
"$push": {
"sku": "$_id.sku",
"qty": "$qty",
"price": "$price"
}
}
}}
])

Related

mongodb $lookup return empty array

I'm new to mongodb and in this question I have 2 collections, one is selected_date, another is global_mobility_report, what I'm trying to do is to find entries in global_mobility_report whose date is in the selected_date so I use $lookup to join the two collections.
date_selected:
{
"_id" : ObjectId("5f60d81ba43174cf172ebfdc"),
"date" : ISODate("2020-05-22T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfdd"),
"date" : ISODate("2020-05-23T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfde"),
"date" : ISODate("2020-05-24T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfdf"),
"date" : ISODate("2020-05-25T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfe0"),
"date" : ISODate("2020-05-26T00:00:00.000+08:00")
},
{
"_id" : ObjectId("5f60d81ba43174cf172ebfe1"),
"date" : ISODate("2020-05-27T00:00:00.000+08:00")
}
global_mobility_report:
{
"_id" : ObjectId("5f49fb013acddb5eec37f99e"),
"country_region_code" : "AE",
"country_region" : "United Arab Emirates",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-15",
"retail_and_recreation_percent_change_from_baseline" : "0",
"grocery_and_pharmacy_percent_change_from_baseline" : "4",
"parks_percent_change_from_baseline" : "5",
"transit_stations_percent_change_from_baseline" : "0",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "1"
},
{
"_id" : ObjectId("5f49fb013acddb5eec37f99f"),
"country_region_code" : "AE",
"country_region" : "United Arab Emirates",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-16",
"retail_and_recreation_percent_change_from_baseline" : "1",
"grocery_and_pharmacy_percent_change_from_baseline" : "4",
"parks_percent_change_from_baseline" : "4",
"transit_stations_percent_change_from_baseline" : "1",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "1"
},
{
"_id" : ObjectId("5f49fb013acddb5eec37f9a0"),
"country_region_code" : "AE",
"country_region" : "United Arab Emirates",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-17",
"retail_and_recreation_percent_change_from_baseline" : "-1",
"grocery_and_pharmacy_percent_change_from_baseline" : "1",
"parks_percent_change_from_baseline" : "5",
"transit_stations_percent_change_from_baseline" : "1",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "1"
},
{
"_id" : ObjectId("5f49fb013acddb5eec37f9a1"),
"country_region_code" : "AE",
"country_region" : "United Arab Emirates",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-18",
"retail_and_recreation_percent_change_from_baseline" : "-2",
"grocery_and_pharmacy_percent_change_from_baseline" : "1",
"parks_percent_change_from_baseline" : "5",
"transit_stations_percent_change_from_baseline" : "0",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "1"
}
when I try to find all entries in global with 'date' match in selected_date(I have converted the string to data format in gobal_mobility_report), it returns empty array.
db.global_mobility_report.aggregate([
{$match:{country_region:"Indonesia"}},
{$addFields: {"dateconverted": {$convert: { input: "$date", to: "date", onError:"onErrorExpr", onNull:"onNullExpr"}:}}},
{
$lookup:
{
from: "selected_date",
localField:"dateconverted",
foreignField: "date",
as: "selected_dates" // empty
}
})]
The output is:
{
"_id" : ObjectId("5f49fd6a3acddb5eec4427bb"),
"country_region_code" : "ID",
"country_region" : "Indonesia",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-15",
"retail_and_recreation_percent_change_from_baseline" : "-2",
"grocery_and_pharmacy_percent_change_from_baseline" : "-2",
"parks_percent_change_from_baseline" : "-8",
"transit_stations_percent_change_from_baseline" : "1",
"workplaces_percent_change_from_baseline" : "5",
"residential_percent_change_from_baseline" : "1",
"dateconverted" : ISODate("2020-02-15T08:00:00.000+08:00"),
"selected_dates" : [ ]
},
{
"_id" : ObjectId("5f49fd6a3acddb5eec4427bc"),
"country_region_code" : "ID",
"country_region" : "Indonesia",
"sub_region_1" : "",
"sub_region_2" : "",
"metro_area" : "",
"iso_3166_2_code" : "",
"census_fips_code" : "",
"date" : "2020-02-16",
"retail_and_recreation_percent_change_from_baseline" : "-3",
"grocery_and_pharmacy_percent_change_from_baseline" : "-3",
"parks_percent_change_from_baseline" : "-7",
"transit_stations_percent_change_from_baseline" : "-4",
"workplaces_percent_change_from_baseline" : "2",
"residential_percent_change_from_baseline" : "2",
"dateconverted" : ISODate("2020-02-16T08:00:00.000+08:00"),
"selected_dates" : [ ]
}
The reason you are getting an empty array is because dateconverted does not match the date field.
The $lookup operator does an equality between the localField and the foreigntField field, so basically with an example
db.users.insertMany([
{ email: "test#example.com", userId: 0 },
{ email: "test2#example.com", userId: 1 },
{ email: "test3#example.com", userId: 2 },
{ email: "test3#example.com", userId: 3 }
]);
db.posts.insertMany([
{ by: 0, post: "hello world" },
{ by: 0 , post: "hello earthlings" },
{ by: 3, post: "test test test"}
]);
db.posts.aggregate([
{
$lookup: {
from: "users",
localField: "by",
foreignField: "userId",
as: "list_of_post"
}
}
]).toArray();
The output will be what it suppose to be, because the localField matched the ForeignField
[
{
"_id" : ObjectId("5f60f6859a6df3133b325eb0"),
"by" : 0,
"post" : "hello world",
"list_of_post" : [
{
"_id" : ObjectId("5f60f6849a6df3133b325eac"),
"email" : "test#example.com",
"userId" : 0
}
]
},
{
"_id" : ObjectId("5f60f6859a6df3133b325eb1"),
"by" : 0,
"post" : "hello earthlings",
"list_of_post" : [
{
"_id" : ObjectId("5f60f6849a6df3133b325eac"),
"email" : "test#example.com",
"userId" : 0
}
]
},
{
"_id" : ObjectId("5f60f6859a6df3133b325eb2"),
"by" : 3,
"post" : "test test test",
"list_of_post" : [
{
"_id" : ObjectId("5f60f6849a6df3133b325eaf"),
"email" : "test3#example.com",
"userId" : 3
}
]
}
]
Let's mimic a situation where it does not match
db.posts.drop();
db.posts.insertMany([
{ by: 20, post: "hello world" },
{ by: 23 , post: "hello earthlings" },
{ by: 50, post: "test test test"}
]);
We get an empty array
[
{
"_id" : ObjectId("5f60f83344304796ae700b4d"),
"by" : 20,
"post" : "hello world",
"list_of_post" : [ ]
},
{
"_id" : ObjectId("5f60f83344304796ae700b4e"),
"by" : 23,
"post" : "hello earthlings",
"list_of_post" : [ ]
},
{
"_id" : ObjectId("5f60f83344304796ae700b4f"),
"by" : 50,
"post" : "test test test",
"list_of_post" : [ ]
}
]
So, back to your question, the reason for the empty array is as a result of the dateconverted field not matching the date field. So, let's take a look at an example.
In the first document the dateconverted is
ISODate("2020-02-16T08:00:00.000+08:00") and checking at date_selected document , there is no field that correspond to this value ISODate("2020-02-16T08:00:00.000+08:00"). But let's manually insert this, so you will properly understand what I am talking about.
db.date_selected.insert({
"_id" : ObjectId(),
"date": ISODate("2020-02-16T08:00:00.000+08:00")
});
Running the aggregation pipeline will also make selected_dates an empty array. And the other thing you have to note is that the mm/dd/yyy part of the ISODate object does not also match any document in your question. Secondly, you have to devise another means of running the comparison, because the aggregation pipeline in the $addFileds stage will be affected by timezone and other issues as well.

elemMatch doesn't retrieve data from [ ] brackets in MongoDB

Structure of collection:
{
"address": {
"building": "1007",
"coord": [ -73.856077, 40.848447 ],
"street": "Morris Park Ave",
"zipcode": "10462"
},
"borough": "Bronx",
"cuisine": "Bakery",
"grades": [
{ "date": { "$date": 1393804800000 }, "grade": "A", "score": 2 },
{ "date": { "$date": 1378857600000 }, "grade": "A", "score": 6 },
{ "date": { "$date": 1358985600000 }, "grade": "A", "score": 10 },
{ "date": { "$date": 1322006400000 }, "grade": "A", "score": 9 },
{ "date": { "$date": 1299715200000 }, "grade": "B", "score": 14 }
],
"name": "Morris Park Bake Shop",
"restaurant_id": "30075445"
}
The first query below doesn't return any results, second does. Why?
"coord": [ -73.856077, 40.848447 ] Here coord is an array of two elements so why isn't elemMatch returning anything?
> db.restaurants.find({address : { $elemMatch: { coord: {$lt : -95.754168}}}});
>
>
> db.restaurants.find({"address.coord" : {$lt : -95.754168}});
{ "_id" : ObjectId("5ed53c72c7494f71176bafb9"), "address" : { "building" : "3707", "coord" : [ -101.8945214, 33.5197474 ], "street" : "82 Street", "zipcode" : "11372" }, "borough" : "Queens", "cuisine" : "American ", "grades" : [ { "date" : ISODate("2014-06-04T00:00:00Z"), "grade" : "A", "score" : 12 }, { "date" : ISODate("2013-11-07T00:00:00Z"), "grade" : "B", "score" : 19 }, { "date" : ISODate("2013-05-17T00:00:00Z"), "grade" : "A", "score" : 11 }, { "date" : ISODate("2012-08-29T00:00:00Z"), "grade" : "A", "score" : 11 }, { "date" : ISODate("2012-04-03T00:00:00Z"), "grade" : "A", "score" : 12 }, { "date" : ISODate("2011-11-16T00:00:00Z"), "grade" : "A", "score" : 7 } ], "name" : "Burger King", "restaurant_id" : "40534067" }
{ "_id" : ObjectId("5ed53c72c7494f71176bb325"), "address" : { "building" : "15259", "coord" : [ -119.6368672, 36.2504996 ], "street" : "10 Avenue", "zipcode" : "11357" }, "borough" : "Queens", "cuisine" : "Italian", "grades" : [ { "date" : ISODate("2014-09-04T00:00:00Z"), "grade" : "A", "score" : 11 }, { "date" : ISODate("2014-03-26T00:00:00Z"), "grade" : "A", "score" : 8 }, { "date" : ISODate("2013-03-04T00:00:00Z"), "grade" : "A", "score" : 10 }, { "date" : ISODate("2012-09-27T00:00:00Z"), "grade" : "A", "score" : 10 }, { "date" : ISODate("2012-04-20T00:00:00Z"), "grade" : "A", "score" : 7 }, { "date" : ISODate("2011-11-23T00:00:00Z"), "grade" : "C", "score" : 34 } ], "name" : "Cascarino'S", "restaurant_id" : "40668681" }
{ "_id" : ObjectId("5ed53c72c7494f71176bb7c8"), "address" : { "building" : "60", "coord" : [ -111.9975205, 42.0970258 ], "street" : "West Side Highway", "zipcode" : "10006" }, "borough" : "Manhattan", "cuisine" : "Japanese", "grades" : [ { "date" : ISODate("2014-03-20T00:00:00Z"), "grade" : "A", "score" : 9 }, { "date" : ISODate("2013-06-28T00:00:00Z"), "grade" : "A", "score" : 11 }, { "date" : ISODate("2012-07-05T00:00:00Z"), "grade" : "A", "score" : 13 }, { "date" : ISODate("2011-07-27T00:00:00Z"), "grade" : "A", "score" : 2 } ], "name" : "Sports Center At Chelsea Piers (Sushi Bar)", "restaurant_id" : "40882356" }
The reason:
Your array doesn't contain valid element.
Smallest value in negative is the greatest value. So -73 is > than -95 and 40 is > -95.
Play
And other works. play
Both formats are valid. But data(mentioned coord) is also not matching the query in both the formats.
It is not finding the records because the schema would be different when translated.
For example: if you change your schema to the following, it will return the document:
{
"address": [{
"building": "1007",
"coord": [ -73.856077, 40.848447 ],
"street": "Morris Park Ave",
"zipcode": "10462"
}],
"borough": "Bronx",
"cuisine": "Bakery",
"grades": [
{ "date": { "$date": 1393804800000 }, "grade": "A", "score": 2 },
{ "date": { "$date": 1378857600000 }, "grade": "A", "score": 6 },
{ "date": { "$date": 1358985600000 }, "grade": "A", "score": 10 },
{ "date": { "$date": 1322006400000 }, "grade": "A", "score": 9 },
{ "date": { "$date": 1299715200000 }, "grade": "B", "score": 14 }
],
"name": "Morris Park Bake Shop",
"restaurant_id": "30075445"
}
Notice the square brackets around address sub-document.
Please follow this link for more reference https://docs.mongodb.com/manual/reference/operator/query/elemMatch/#array-of-embedded-documents

MongoDB Aggregation

I have a the following collection
{ "data" :[
{ "country" :"USA", "state": "NJ", "County" : "Middlesex", "city" : "Edison", "population" :0923422 },
{ "country" :"USA", "state": "NJ", "County" : "Mercer", "city" : "Princeton", "population" :0923422 },
{ "country" :"USA", "state": "NY", "County" : "Middlesex", "city" : "Edison", "population" :234234 },
{ "country" :"USA", "state": "NY", "County" : "Ocean", "city" : "Albony", "population" :234324 },
{ "country" :"USA", "state": "PA", "County" : "Central", "city" : "Edison", "population" :0923422 },
{ "country" :"USA", "state": "NJ", "County" : "Middlesex", "city" : "Edison", "population" :23432 },
{ "country" :"USA", "state": "OH", "County" : "Middlesex", "city" : "Cincinatti", "population" :0923422 },
{ "country" :"USA", "state": "OH", "County" : "Middlesex", "city" : "Columbos", "population" :23432 } ]
}
looking to find the total population by Country, State, County and City with nested aggregation in mongodb.
Please help with query.
Query:-
db.collection.aggregate([
{$group:
{
_id : {"country" : "$country",
"state" : "$state",
"County" : "$County",
"city" : "$city"
},
"totalPopulationOfCity" : {$sum: "$population" }
}},
{$group:
{
_id : {"country" : "$_id.country",
"state" : "$_id.state",
"County" : "$_id.County"
},
"cities" : { $addToSet: {"city" : "$_id.city", "totalPopulationOfCity" : "$totalPopulationOfCity"} } ,
"totalPopulationOfCounty" : {$sum: "$totalPopulationOfCity" }
}},
{$group:
{
_id : {"country" : "$_id.country",
"state" : "$_id.state"
},
"counties" : {$addToSet: {"County": "$_id.County", "cities" : "$cities",
"totalPopulationOfCounty" : "$totalPopulationOfCounty"} } ,
"totalPopulationOfState" : {$sum: "$totalPopulationOfCounty" }
}},
{$group:
{
_id : {"country" : "$_id.country"
},
"states" : {$addToSet : {"state" : "$_id.state", "counties": "$counties", "totalPopulationOfState" : "$totalPopulationOfState"}},
"totalPopulationOfCountry" : {$sum: "$totalPopulationOfState" }
}},
]);
Output:-
/* 1 */
{
"_id" : {
"country" : "USA"
},
"states" : [
{
"state" : "NY",
"counties" : [
{
"County" : "Ocean",
"cities" : [
{
"city" : "Albony",
"totalPopulationOfCity" : 234324
}
],
"totalPopulationOfCounty" : 234324
},
{
"County" : "Middlesex",
"cities" : [
{
"city" : "Edison",
"totalPopulationOfCity" : 234234
}
],
"totalPopulationOfCounty" : 234234
}
],
"totalPopulationOfState" : 468558
},
{
"state" : "NJ",
"counties" : [
{
"County" : "Mercer",
"cities" : [
{
"city" : "Princeton",
"totalPopulationOfCity" : 923422
}
],
"totalPopulationOfCounty" : 923422
},
{
"County" : "Middlesex",
"cities" : [
{
"city" : "Edison",
"totalPopulationOfCity" : 946854
}
],
"totalPopulationOfCounty" : 946854
}
],
"totalPopulationOfState" : 1870276
},
{
"state" : "OH",
"counties" : [
{
"County" : "Middlesex",
"cities" : [
{
"city" : "Cincinatti",
"totalPopulationOfCity" : 923422
},
{
"city" : "Columbos",
"totalPopulationOfCity" : 23432
}
],
"totalPopulationOfCounty" : 946854
}
],
"totalPopulationOfState" : 946854
},
{
"state" : "PA",
"counties" : [
{
"County" : "Central",
"cities" : [
{
"city" : "Edison",
"totalPopulationOfCity" : 923422
}
],
"totalPopulationOfCounty" : 923422
}
],
"totalPopulationOfState" : 923422
}
],
"totalPopulationOfCountry" : 4209110
}
Verification using excel:-

group by date and then by currecny and sum mongo records

I have the following records on my mongo database
> db.orders.find({});
{
"_id" : "WEB3",
"currency" : "USD",
"company" : "b",
"user_id" : "b",
"timestamp" : ISODate("2015-06-26T12:13:18.570Z"),
"details" : {
"ordered" : {
"total" : 1910.4,
"deliveryVAT" : 120,
"delivery" : 600,
"goodsVAT" : 198.4,
"goodsTotal" : 992
}
}
}
{
"_id" : "WEB1",
"currency" : "GBP",
"company" : "a",
"user_id" : "a",
"timestamp" : ISODate("2015-06-26T12:11:08.570Z"),
"details" : {
"ordered" : {
"total" : 1910.4,
"deliveryVAT" : 120,
"delivery" : 600,
"goodsVAT" : 198.4,
"goodsTotal" : 992
}
}
}
{
"_id" : "WEB2",
"currency" : "GBP",
"company" : "a",
"user_id" : "a",
"timestamp" : ISODate("2015-06-26T12:11:18.570Z"),
"details" : {
"ordered" : {
"total" : 1910.4,
"deliveryVAT" : 120,
"delivery" : 600,
"goodsVAT" : 198.4,
"goodsTotal" : 992
}
}
}
here is the insert, statement:
db.orders.insert( { "_id" : "WEB1", "currency" : "GBP", "company" : "a", "user_id" : "a", "timestamp" : ISODate("2015-06-26T12:11:08.570Z"), "details" : { "ordered" : { "total" : 1910.4, "deliveryVAT" : 120, "delivery" : 600, "goodsVAT" : 198.4, "goodsTotal" : 992 } } });
db.orders.insert( { "_id" : "WEB2", "currency" : "GBP", "company" : "a", "user_id" : "a", "timestamp" : ISODate("2015-06-26T12:11:18.570Z"), "details" : { "ordered" : { "total" : 1910.4, "deliveryVAT" : 120, "delivery" : 600, "goodsVAT" : 198.4, "goodsTotal" : 992 } } });
db.orders.insert( { "_id" : "WEB3", "currency" : "USD", "company" : "b", "user_id" : "b", "timestamp" : ISODate("2015-06-26T12:13:18.570Z"), "details" : { "ordered" : { "total" : 1910.4, "deliveryVAT" : 120, "delivery" : 600, "goodsVAT" : 198.4, "goodsTotal" : 992 } } });
What is the correct way to group by date and then group by currency, so that I get a result similar to:
{ [ "date": "2015-06-26",
"currency": "USD",
"total": 1910.4,
"no_of_orders": 1],
[ "date": "2015-06-26",
"currency": "GBP",
"total": 3820.8,
"no_of_orders": 2]]
}
From a previous post mongodb sort result of aggregate query and display day name I am able to get the number of orders made for each day, but then I am unsure how to pipe the results and split those by currency and then total the result?
Any advice much appreciated
You could try the following aggregation pipeline which groups the documents by Year-Month-Day and the currency to get the desired results:
db.orders.aggregate([
{
"$group": {
"_id": {
"day": { "$dayOfMonth" : "$timestamp" },
"month": { "$month" : "$timestamp" },
"year": { "$year" : "$timestamp" },
"currency": "$currency"
},
"total": { "$sum": "$details.ordered.total" },
"no_of_orders": { "$sum": 1 }
}
},
{
"$project": {
"_id": 0,
"dateDay": {
"$concat": [
{"$substr" : [ "$_id.day", 0, 2]}, "-",
{"$substr" : [ "$_id.month", 0, 2]}, "-",
{"$substr" : [ "$_id.year", 0, 4]}
]
},
"total": 1,
"no_of_orders": 1,
"currency": "$_id.currency"
}
}
])
Sample Output
/* 0 */
{
"result" : [
{
"total" : 1910.4,
"no_of_orders" : 1,
"dateDay" : "26-6-2015",
"currency" : "USD"
},
{
"total" : 3820.8,
"no_of_orders" : 2,
"dateDay" : "26-6-2015",
"currency" : "GBP"
}
],
"ok" : 1
}

How to find count of a key in one document using mongoDB?

I have following structure in my collection:
users:[
{
"name":"ABC",
"address":{
"city":"London",
"country":"UK",
}
},
{
"name":"XYZ",
"address":{
"city":"London",
"country":"UK",
}
},
{
"name":"PQR",
"address":{
"city":"NewYork",
"country":"US",
}
}
]
I want count of number of occurrences of 'city' key in 'address' and 'name' as a result.
I want to query above collection and want following output:
[{
"name":"ABC",
"city":"London",
"count":2
},{
"name":"XYZ",
"city":"London",
"count":2
}, {
"name":"PQR",
"city":"NewYork",
"count":1
}
]
I simulated your collection
{
"_id" : ObjectId("547c30ae371ea419f07b9550"),
"users" : [
{
"name" : "ABC",
"address" : {
"city" : "London",
"country" : "UK"
}
},
{
"name" : "XYZ",
"address" : {
"city" : "London",
"country" : "UK"
}
},
{
"name" : "PQR",
"address" : {
"city" : "NewYork",
"country" : "US"
}
}
]
}
And then I use aggregate framework
db.coll.aggregate([
{
$unwind:"$users"
},
{
$group:{
_id:"$users.address.city",
name:{$push:"$users.name"},
city:{$first:"$users.address.city"},
count:{$sum:1}
}
},{
$unwind:"$name"
},{
$project:{
_id:0,
"city":"$_id",
"name":1,
"city":1,
"count":1
}
}])
result:
{
"result" : [
{
"name" : "PQR",
"city" : "NewYork",
"count" : 1
},
{
"name" : "ABC",
"city" : "London",
"count" : 2
},
{
"name" : "XYZ",
"city" : "London",
"count" : 2
}
],
"ok" : 1
}
UPDATE AFTER QUESTION
I added a new Document
{
"_id" : ObjectId("547c394c371ea419f07b9551"),
"users" : [
{
"address" : {
"city" : "Livorno",
"country" : "LI"
}
},
{
"address" : {
"city" : "Livorno",
"country" : "LI"
}
},
{
"address" : {
"city" : "NewYork",
"country" : "US"
}
}
]
}
and new Query
db.coll.aggregate([
{
$unwind:"$users"
},
{
$group:{
_id:"$users.address.city",
"name": {
$push:{"$ifNull": ["$users.name","$_id"]}
},
city:{$first:"$users.address.city"},
count:{$sum:1}
}
},{
$unwind:"$name"
},{
$project:{
_id:0,
"city":"$_id",
"name":1,
"city":1,
"count":1
}
}])
Result:
{
"result" : [
{
"name" : "PQR",
"city" : "NewYork",
"count" : 2
},
{
"name" : ObjectId("547c394c371ea419f07b9551"),
"city" : "NewYork",
"count" : 2
},
{
"name" : ObjectId("547c394c371ea419f07b9551"),
"city" : "Livorno",
"count" : 2
},
{
"name" : ObjectId("547c394c371ea419f07b9551"),
"city" : "Livorno",
"count" : 2
},
{
"name" : "ABC",
"city" : "London",
"count" : 2
},
{
"name" : "XYZ",
"city" : "London",
"count" : 2
}
],
"ok" : 1
}