get $sum of items in the same document mongodb - mongodb

/* 1 */
{
"_id" : ObjectId("5941240cdc8dd12a183337b0"),
"item" : ObjectId("593e700d9f34350aac73231d"),
"store" : ObjectId("593e7589a489ce07c899210d"),
"itemcredits" : [
{
"expireDate" : "10/2019",
"unitePrice" : "50",
"itemCredit" : "5"
},
{
"expireDate" : "12/2018",
"unitePrice" : "50",
"itemCredit" : "3"
}
]
}
i want to query to get the total sum of itemcredits.itemCredit of the same document that match same store and item to get the result = 8 for this example

Try some thing like this
db.collectionName.aggregate([{$group: {
'_id': '$_id',
"total": {$sum: "$itemcredits.itemcredits" }
}}]);
itemcredits need to be integer

Related

Aggregate (group by) query in MongoDB by 2 fields

I am using MongoDB. My collection object structure is like the following:
{
"_id" : ObjectId("5a58800acebcda57188bf0aa"),
"title" : "Article title",
"categories" : "politics",
"url" : "https://example.com",
"article_date" : ISODate("2018-01-11T10:00:00.000Z"),
"content" : "content here..."
},
{
"_id" : ObjectId("5a58800acebcda57188bf0aa"),
"title" : "Article title 2",
"categories" : "economics",
"url" : "https://example.com",
"article_date" : ISODate("2018-01-12T10:00:00.000Z"),
"content" : "content here..."
}
Articles are publishing each day and I have many categories.
How can I group the data by date and count documents by specific category, for example:
{
"date": ISODate("2018-01-11T10:00:00.000Z"),
"result": [{
"category": "politics",
"count": 2
}, {
"category": "economics",
"count": 1
}]
},
{
"date": ISODate("2018-01-12T10:00:00.000Z"),
"result": [{
"category": "politics",
"count": 2
}, {
"category": "economics",
"count": 1
}]
}
Thank you in advance
you need to $group twice to get the result, first by article_date and categories then $group on article_date
db.art.aggregate([
{$group : {
_id : {article_date : "$article_date", categories : "$categories"},
count : {$sum : 1}
}},
{$group : {
_id : {article_date : "$_id.article_date"},
result : {$push : {category : "$_id.categories", count : "$count"}}
}},
{$addFields :{
_id : "$_id.article_date"
}}
]).pretty()
result for sample data in question
{
"_id" : ISODate("2018-01-11T10:00:00Z"),
"result" : [
{
"category" : "politics",
"count" : 1
}
]
}
{
"_id" : ISODate("2018-01-12T10:00:00Z"),
"result" : [
{
"category" : "economics",
"count" : 1
}
]
}

Mongo DB - Group By and Having Implementation

I'm trying to write a Mongo DB query where I do the following,
JSON list - Representing documents in my collection,
Industry[]:
{
"_id" : ObjectId("57aa6058be0c853c8cee34cd"),
"options": {
"paramList" : [
{
"name" : "industryCategory",
"value" : "Travel",
"mandatory" : true
},
{
"name" : "someOtherThing",
"value" : "dontMind",
"mandatory" : true
}
]
}
"mostRecent" : true
},
{
"_id" : ObjectId("57aa6058be0c853c8cee34cd"),
"options": {
"paramList" : [
{
"name" : "industryCategory",
"value" : "Dining",
"mandatory" : true
},
{
"name" : "someOtherThing",
"value" : "dontMind",
"mandatory" : true
}
]
}
"mostRecent" : true
},
{
"_id" : ObjectId("57aa6058be0c853c8cee34cd"),
"options": {
"paramList" : [
{
"name" : "industryCategory",
"value" : "Travel",
"mandatory" : true
},
{
"name" : "someOtherThing",
"value" : "dontMind",
"mandatory" : true
}
]
}
"mostRecent" : true
}
I'm trying to group and get a count of values for those paramList - values where name is industryCategory. Essentially, the output I am looking for is something like this,
Travel: 2
Dining: 1
I'm trying to do the following,
Industry is the name of the collection,
db.Industry.aggregate (
[
{$match: {mostRecent: true}},
{$group: {
_id: '$options.paramList.value',
count: {$sum: 1}
}},
{$match: {'options.paramList.name': 'industryCategory'}}
])
I'm getting an empty result. Please suggest what I can do
Well, I didn't have anyone answering. But, in the meanwhile I managed to figure it out myself. Posting the answer below,
aggregate (
[
{"$match": {mostRecent: true}},
{"$unwind" : "$options.paramList"},
{"$group" :
{
_id: "$options.paramList.value",
count: {$sum : 1}
}
}
]
Essentially, use unwind wherever you have to iterate over arrays (a list of sub-documents). This has been a productive learning, at least for me.

MongoDB filtering out subdocuments with lookup aggregation

Our project database has a capped collection called values which gets updated every few minutes with new data from sensors. These sensors all belong to a single sensor node, and I would like to query the last data from these nodes in a single aggregation. The problem I am having is filtering out just the last of ALL the types of sensors while still having only one (efficient) query. I looked around and found the $group argument, but I can't seem to figure out how to use it correctly in this case.
The database is structured as follows:
nodes:
{
"_id": 681
"sensors": [
{
"type": "foo"
},
{
"type": "bar"
}
]
}
values:
{
"_id" : ObjectId("570cc8b6ac55850d5740784e"),
"timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
"type" : "foo",
"nodeid" : 681,
"value" : 10
}
{
"_id" : ObjectId("190ac8b6ac55850d5740776e"),
"timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
"type" : "bar",
"nodeid" : 681,
"value" : 20
}
{
"_id" : ObjectId("167bc997bb66750d5740665e"),
"timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
"type" : "bar",
"nodeid" : 200,
"value" : 20
}
{
"_id" : ObjectId("110cc9c6ac55850d5740784e"),
"timestamp" : ISODate("2016-04-09T12:06:46.344Z"),
"type" : "foo",
"nodeid" : 681,
"value" : 12
}
so let's imagine I want the data from node 681, I would want a structure like this:
nodes:
{
"_id": 681
"sensors": [
{
"_id" : ObjectId("570cc8b6ac55850d5740784e"),
"timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
"type" : "foo",
"nodeid" : 681,
"value" : 10
},
{
"_id" : ObjectId("190ac8b6ac55850d5740776e"),
"timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
"type" : "bar",
"nodeid" : 681,
"value" : 20
}
]
}
Notice how one value of foo is not queried, because I want to only get the latest value possible if there are more than one value (which is always going to be the case). The ordering of the collection is already according to the timestamp because the collection is capped.
I have this query, but it just gets all the values from the database (which is waaay too much to do in a lifetime, let alone one request of the web app), so I was wondering how I would filter it before it gets aggregated.
query:
db.nodes.aggregate(
[
{
$unwind: "$sensors"
},
{
$match:{
nodeid: 681
}
},
{
$lookup:{
from: "values", localField: "sensors.type", foreignField: "type", as: "sensors"
}
}
}
]
)
Try this
// Pipeline
[
// Stage 1 - sort the data collection if not already done (optional)
{
$sort: {
"timestamp":1
}
},
// Stage 2 - group by type & nodeid then get first item found in each group
{
$group: {
"_id":{type:"$type",nodeid:"$nodeid"},
"sensors": {"$first":"$$CURRENT"} //consider using $last if your collection is on reverse
}
},
// Stage 3 - project the fields in desired
{
$project: {
"_id":"$sensors._id",
"timestamp":"$sensors.timestamp",
"type":"$sensors.type",
"nodeid":"$sensors.nodeid",
"value":"$sensors.value"
}
},
// Stage 4 - group and push it to array sensors
{
$group: {
"_id":{nodeid:"$nodeid"},
"sensors": {"$addToSet":"$$CURRENT"}
}
}
]
as far as I got document structure, there is no need to use $lookup as all data is in readings(values) collection.
Please see proposed solution:
db.readings.aggregate([{
$match : {
nodeid : 681
}
},
{
$group : {
_id : {
type : "$type",
nodeid : "$nodeid"
},
readings : {
$push : {
timestamp : "$timestamp",
value : "$value",
id : "$_id"
}
}
}
}, {
$project : {
_id : "$_id",
readings : {
$slice : ["$readings", -1]
}
}
}, {
$unwind : "$readings"
}, {
$project : {
_id : "$readings.id",
type : "$_id.type",
nodeid : "$_id.nodeid",
timestamp : "$readings.timestamp",
value : "$readings.value",
}
}, {
$group : {
_id : "$nodeid",
sensors : {
$push : {
_id : "$_id",
timestamp : "$timestamp",
value : "$value",
type:"$type"
}
}
}
}
])
and output:
{
"_id" : 681,
"sensors" : [
{
"_id" : ObjectId("110cc9c6ac55850d5740784e"),
"timestamp" : ISODate("2016-04-09T12:06:46.344Z"),
"value" : 12,
"type" : "foo"
},
{
"_id" : ObjectId("190ac8b6ac55850d5740776e"),
"timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
"value" : 20,
"type" : "bar"
}
]
}
Any comments welcome!

Filter aggregations in mongodb

Say I'm acting on a collection of documents that look like this:
{
"_id" : ObjectId("552712c3f92ea17426000ace"),
"product" : "Mobile Safari",
"venue_id" : NumberLong(71540),
"uid" : "dd542fea6b4443469ff7bf1f56472eac",
"ag" : 0,
"promo" : "bc40100abc8d4eb6a0c68f81f4a756c7",
"promo_f" : NumberLong(1),
"brand" : NumberLong(17),
"venue" : "ovation_2480",
"lt" : 0,
"ts" : ISODate("2015-04-10T00:01:07.734Z"),
"evt" : "login",
"mac" : "00:00:00:00:00:00",
"__ns__" : "wifipromo",
"pvdr" : NumberLong(42),
"os" : "iPhone",
"cmpgn" : "fc6de34aef8b4f57af0b8fda98d8c530",
"ip" : "192.119.43.250",
"lng" : 0,
"product_ver" : "8"
}
I want to count the total amount of aggregate documents with the same uid.
I use this:
db.events_2015_04_10.aggregate([
{
$group: {
_id: "$uid",
count: {
$sum: 1
}
}
}
]);
But lets say I want only a list of aggregations that don't contain evt: "login." In short I only want to aggregate by uid only if all documents with that uid do not have evt: "login."
how would I do that?
You were almost there. Use $match with the $ne operator.
db.events_2015_04_10.aggregate([
{ "$match": { "evt": { "$ne": "login" }}},
{ "$group": { "_id": "$uid", "count": { "$sum": 1 }}}
])

MongoDB $ne in sub documents

{
"_id" : ObjectId("53692eb238ed04c824679f18"),
"firstUserId" : 1,
"secondUserId" : 17,
"messages" : [
{
"_id" : ObjectId("5369338997b964b81d579fc6"),
"read" : true,
"dateTime" : 1399403401,
"message" : "d",
"userId" : 1
},
{
"_id" : ObjectId("536933c797b964b81d579fc7"),
"read" : false,
"dateTime" : 1399403463,
"message" : "asdf",
"userId" : 17
}
]
}
I'm trying to select all documents that have firstUserId = 1 and also have sub documents
that have userId differnet ($ne) to 1 and read = false.
I tried:
db.usermessages.find({firstUserId: 1, "messages.userId": {$ne: 1}, "messages.read": false})
But it returns empty cause messages have both 1 and 17.
And also how to count subdocuments that have given case?
Are you trying to get the count of all the documents which are returned after your match criteria? If Yes, then you might consider using aggregation framework. http://docs.mongodb.org/manual/aggregation/
Something like below could be done to get you the counts:
db.usermessages.aggregate(
{ "$unwind": "$messages" },
{ "$match":
{ "firstUserId": 1,
"messages.userId": { "$ne" : 1},
"messages.read": false
}
},
{ "$group": { "_id" :null, "count" : { "$sum": 1 } } }
)
Hope this helps.
PS: I have not tried this on my system.