Aggregate based on Array value - mongodb

I have collection schema like :
{
"_id" : ObjectId("582ee289618a504e5c830e03"),
"updatedAt" : ISODate("2016-11-24T05:01:59.470Z"),
"createdAt" : ISODate("2016-11-18T11:14:17.912Z"),
"requestId" : "IER5R2H",
"pickupDetails" : {
"_id" : ObjectId("58367447b0a1ada74ad7af7e"),
"itemsCount" : 1,
"pickupItems" : [
{
"name" : "Newspaper",
"quantity" : 15,
"unit" : "kg",
"unitPrice" : 9,
"amount" : 135,
"_id" : ObjectId("58367447b0a1ada74ad7af7f")
}
]
}}
{
"_id" : ObjectId("58fff31a618a504e5c831191"),
"updatedAt" : ISODate("2016-11-21T13:37:51.267Z"),
"createdAt" : ISODate("2016-11-19T06:37:14.857Z"),
"requestId" : "M7OZY9O",
"pickupDetails" : {
"_id" : ObjectId("5832f8afb8ec77fa3c518f97"),
"itemsCount" : 2,
"pickupItems" : [
{
"name" : "Newspaper",
"quantity" : 18,
"unit" : "kg",
"unitPrice" : 11,
"amount" : 198,
"_id" : ObjectId("5832f8afb8ec77fa3c518f98")
},
{
"name" : "Plastic",
"quantity" : 4,
"unit" : "kg",
"unitPrice" : 11,
"amount" : 44,
"_id" : ObjectId("584a853e46c71be3585bfb5a")
}
]
}}
I need to add the quantity based on the name of pickupItems, like "Newspaper" etc. Suppose quantity of Newspaper for a particular day.
As per the below data, result should be like, {"Newspaper":33}, for a particular date.

try this :
db.collection.aggregate([
{
$unwind:"$pickupDetails.pickupItems"
},
{
$group:{
_id:"$pickupDetails.pickupItems.name",
quantity:{
$sum:"$pickupDetails.pickupItems.quantity"
}
}
}
])
output:
{ "_id" : "Plastic", "quantity" : 4 }
{ "_id" : "Newspaper", "quantity" : 33 }
you can add a $match stage at the begining of the pipeline to get results for a particular day

Related

MongoDB - how to optimise find query with regex search, with sort

I need to execute the following query:
db.S12_RU.find({"venue.raw":a,"title":/b|c|d|e/}).sort({"year":-1}).skip(X).limit(Y);
where X and Y are numbers.
The number of documents in my collection is:
208915369
Currently, this sort of query takes about 6 minutes to execute.
I have the following indexes:
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_"
},
{
"v" : 2,
"key" : {
"venue.raw" : 1
},
"name" : "venue.raw_1"
},
{
"v" : 2,
"key" : {
"venue.raw" : 1,
"title" : 1,
"year" : -1
},
"name" : "venue.raw_1_title_1_year_-1"
}
]
A standard document looks like this:
{ "_id" : ObjectId("5fc25fc091e3146fb10484af"), "id" : "1967181478", "title" : "Quality of Life of Swedish Women with Fibromyalgia Syndrome, Rheumatoid Arthritis or Systemic Lupus Erythematosus", "authors" : [ { "name" : "Carol S. Burckhardt", "id" : "2052326732" }, { "name" : "Birgitha Archenholtz", "id" : "2800742121" }, { "name" : "Kaisa Mannerkorpi", "id" : "240289002" }, { "name" : "Anders Bjelle", "id" : "2419758571" } ], "venue" : { "raw" : "Journal of Musculoskeletal Pain", "id" : "49327845" }, "year" : 1993, "n_citation" : 31, "page_start" : "199", "page_end" : "207", "doc_type" : "Journal", "publisher" : "Taylor & Francis", "volume" : "1", "issue" : "", "doi" : "10.1300/J094v01n03_20" }
Is there any way to make this query execute in a few seconds?

How to return all documents using $group in mongo aggregation

I have a mongodb pipleline that i'm building up. It's working fine, except that I have an issue in my group stage.
'JURISDICTION'=>['$first'=> '$JURISDICTION'],
I'm only getting documents that match the first value, when they're are multiple values. Any ideas?
Since you have used $first, it will only return the first document, You can use $push to get all the records.
An Example:
For the database entry :
{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") }
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") }
{ "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") }
{ "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") }
{ "_id" : 6, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-15T12:05:10Z") }
{ "_id" : 7, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T14:12:12Z") }
You can use this aggregation query which uses push
db.sales.aggregate(
[
{
$group:
{
_id: { day: { $dayOfYear: "$date"}, year: { $year: "$date" } },
itemsSold: { $push: { item: "$item", quantity: "$quantity" } }
}
}
]
)
And the result is a list of items in itemSold
{
"_id" : { "day" : 46, "year" : 2014 },
"itemsSold" : [
{ "item" : "abc", "quantity" : 10 },
{ "item" : "xyz", "quantity" : 10 },
{ "item" : "xyz", "quantity" : 5 },
{ "item" : "xyz", "quantity" : 10 }
]
}
{
"_id" : { "day" : 34, "year" : 2014 },
"itemsSold" : [
{ "item" : "jkl", "quantity" : 1 },
{ "item" : "xyz", "quantity" : 5 }
]
}
{
"_id" : { "day" : 1, "year" : 2014 },
"itemsSold" : [ { "item" : "abc", "quantity" : 2 } ]
}
Reference: $push

how to get the aggregate sum on a set of fields with the same values using mongo

I am trying to find the sum of documents which have the same values on a set of fields using mongo shell, these are sample documents,
{
"id" : "1",
"date" : ISODate("2017-04-29T00:00:00.000Z"),
"amount" : 697,
"name" : "vendor1"
}
{
"id" : "2",
"date" : ISODate("2017-04-29T00:00:00.000Z"),
"amount" : 380
"name" : "vendor2"
}
{
"id" : "2",
"date" : ISODate("2017-04-29T00:00:00.000Z"),
"amount" : 380,
"name" : "vendor2"
}
{
"id" : "3",
"date" : ISODate("2017-04-29T00:00:00.000Z"),
"amount" : 702,
"name" : "vendor3"
}
{
"id" : "3",
"date" : ISODate("2017-04-29T00:00:00.000Z"),
"amount" : 702,
"name" : "vendor3"
}
the query I have tried is,
db.results.aggregate([
{$group:{'_id':{name:'$name', id:'$id', date:'$date', amount:'$amount',
count:{'$sum':1}}}},
{$match:{'count':{'$gt':1}}}])
but it fetched 0 records. Also I like to know how many such documents have been found, So I am wondering how to solve the issue.
You can use this.
db.results.aggregate([
{ $group:{'_id': {name:'$name', id:'$id', date:'$date', amount:'$amount'}
, count: {$sum: 1} } }
])
Result:
{ "_id" : { "name" : "vendor3", "id" : "3", "date" : ISODate("2017-04-29T00:00:00Z"), "amount" : 702 }, "count" : 2 }
{ "_id" : { "name" : "vendor2", "id" : "2", "date" : ISODate("2017-04-29T00:00:00Z"), "amount" : 380 }, "count" : 2 }
{ "_id" : { "name" : "vendor1", "id" : "1", "date" : ISODate("2017-04-29T00:00:00Z"), "amount" : 697 }, "count" : 1 }

Float number overflows when export MongDB collection to JSON via mongoexport

I'm new to MongoDB. I've inserted a float number into a collection. However, when I export that collection via mongoexport, the float number changes.
This is what in the database:
{ "_id" : ObjectId("56653e23a6b56616ba417bcd"), "id" : "601318", "name" : "中国平安", "buy" : [ { "time" : ISODate("2015-06-15T01:30:00Z"), "price" : 86.9, "quantity" : 1000, "value" : 87074.4 } ], "sell" : [ { "time" : ISODate("2015-07-07T01:30:00Z"), "price" : 80.88, "quantity" : 1000, "value" : 80636.76 } ] }
This is when it's exported to json:
{ "_id" : { "$oid" : "56653e23a6b56616ba417bcd" }, "id" : "601318", "name" : "中国平安", "buy" : [ { "time" : { "$date" : "2015-06-15T09:30:00.000+0800" }, "price" : 86.90000000000001, "quantity" : 1000, "value" : 87074.39999999999 } ], "sell" : [ { "time" : { "$date" : "2015-07-07T09:30:00.000+0800" }, "price" : 80.88, "quantity" : 1000, "value" : 80636.75999999999 } ] }
How to avoid this overflow?
Store the value as an integer: 8063676 (cents or whatever).
See this question.

How to group data by Date and compare it by Month MongoDB

I have huge CDR(call detail report) data like this :
{
"_id" : ObjectId("54eecc9a6c6852b9f0575bbb"),
"msisdn" : "9818895866",
"callType" : "NA",
"duration" : 13.5,
"charges" : 200,
"traffic" : "Data",
"Date" : ISODate("2014-02-15T12:15:42.535Z")
}
{
"_id" : ObjectId("54eecc9a6c6852b9f0575bbc"),
"msisdn" : "9818356561",
"callType" : "STD",
"duration" : 20.100000381469727,
"charges" : 100,
"traffic" : "Voice",
"Date" : ISODate("2014-01-09T00:11:14.646Z")
}
{
"_id" : ObjectId("54eecc9a6c6852b9f0575bbd"),
"msisdn" : "9818173670",
"callType" : "NA",
"duration" : 19.399999618530273,
"charges" : 300,
"traffic" : "Data",
"Date" : ISODate("2014-01-13T19:48:47.789Z")
}
{
"_id" : ObjectId("54eecc9a6c6852b9f0575bbe"),
"msisdn" : "9818719936",
"callType" : "Local",
"duration" : 9,
"charges" : 350,
"traffic" : "SMS",
"Date" : ISODate("2014-03-02T10:51:29.846Z")
}
{
"_id" : ObjectId("54eecc9a6c6852b9f0575bbf"),
"msisdn" : "9818612562",
"callType" : "STD",
"duration" : 5.110000133514404,
"charges" : 450,
"traffic" : "Voice",
"Date" : ISODate("2014-01-08T16:41:30.327Z")
}
i want to display usage of TRAFFIC="DATA" Sum of Previous month duration > sum of current month duration * 2
Display only sum of greater msisdn field
i tried this one
db.CDR.aggregate([ { $match : { traffic : "Data" }},{"$group" : {
"_id" : {
"Msisdn" : "$msisdn",
"Month" : "$date"
},
"Total Duration" : {
"$sum" : "$duration"
},
"Count" : {
"$sum" : 1
}
}
}])
It displays all time sum of duration.
I want to group by Month and compare each month and display only greater msisdn.