Mongodb aggregate for nested subdocument field - mongodb

I'm trying to get the sum of "Duration" from mongo subdocument's using aggregate,
Here I have event_id = "5656b3655b9e5c8812000007", I need to get the sum of "Duration" field by matching the event_id = "5656b3655b9e5c8812000007" in above example.
Example:
"history" : [
{
"timestamp" : "2015-10-26 14:39:15",
"event" : "Creation",
"createdby" : "Ws",
"data" : [
{
"crm_base_contact_id" : "1847",
"crm_imported_files_id" : ""
}
]
},
{
"timestamp" : "2015-10-26 15:12:28",
"event" : "Task",
"createdby" : "Auto-Filter",
"data" : [
{
"Campaign ID" : "219",
"Campaign Name" : "ASA",
"Task ID" : "2541639",
"Filter Name" : "ASA",
"Filter ID" : "826"
}
]
},
{
"event_id" : ObjectId("5656b3655b9e5c8812000007"),
"timestamp" : "2015-11-26 08:23:17",
"event" : "Session",
"createdby" : "ABC",
"data" : [
{
"Campaign ID" : "219",
"Task ID" : "2541639",
"viopCalls" : [
{
"timestamp" : "2015-11-26 08:25:42",
"CallID" : "46",
"Duration" : NumberInt(5),
"TelNumber" : "0685356189"
},
{
"timestamp" : "2015-11-26 08:26:13",
"CallID" : "45",
"Duration" : NumberInt(3),
"TelNumber" : "0685356189"
}
]
}
]
}
],
Expected output : Duration : 8
Please can anyone help me to get the sum of duration column !!!

Use can use the following aggregate query:
db.collection.aggregate(
{$unwind: '$history'},
{$match: {'history.event_id': ObjectId("5656b3655b9e5c8812000007")}},
{$unwind: '$history.data'},
{$unwind: '$history.data.viopCalls'},
{$group: {_id: null, duration: {$sum: '$history.data.viopCalls.Duration'}}}
)
Result:
{ "_id" : null, "duration" : 8 }

Related

MOngoDB query to groupby with different fields based on condition to return the latest record

I want to groupby based on condition where my target field can be sender.category or reciever.category based on condition that either of those field belongs to "cat1", and get the last record of each of on sender.id or reciever.id based on createdAt.
Sample Json1:
{
"code" : "34242342",
"name" : "name1",
"amount" : 200,
"sender" : {
"id" : "fsrfsr3242",
"name" : "name2",
"phone" : "12345678",
"category": "cat1"
},
"receiver" : {
"id" : "42342rewr",
"name" : "naem3",
"phone" : "5653679755",
"category": "cat2"
},
"message" : "",
"status" : "done",
"createdAt" : "2019-09-27T09:17:32.597Z"
}
Sample Json2:
{
"code" : "34242342",
"name" : "name1",
"amount" : 200,
"sender" : {
"id" : "fsrfsr3242",
"name" : "name2",
"phone" : "12345678",
"category": "cat3"
},
"receiver" : {
"id" : "42342rewr",
"name" : "naem3",
"phone" : "5653679755",
"category": "cat1"
},
"message" : "",
"status" : "done",
"createdAt" : "2019-09-27T09:17:32.597Z"
}
Query:
[{$match: {
$or: [{ "sender.category": 'cat1' }, {"receiver.category" : 'cat1'}]
}}, {$sort: {
"createdAt": 1
}}, {$group: {
_id: {sender :"$sender.id", reciever : "$receiver.id"},
lastrecord: {
$last: "$$ROOT"
}
}}]
I want to return only the last record, sender.id or receiver.id can have multiple records of which i only want to retrieve the last one. But my query is returning multiple records.
How to get only the last i.e latest one based on above conditions and createdAt?
Sample output:
{
"lastrecord" : {
"name" : "name1",
"amount" : 1000,
"sender" : {
"name" : "name2",
"phone" : "213232141",
"category" : "cat1"
},
"receiver" : {
"name" : "name",
"phone" : "321312412",
"category" : "cat2"
},
"status" : "done",
"createdAt" : "2019-11-25T17:00:17.226+06:30"
}
}
i want this for every sender.id or receiver.id

How to find Immediate Child of a node in mongo db

I have following Collection
Location Collection
[
{id : 1 name : 'l1' , 'location' : pune , parentLocation : Maharashstra},
{id : 2 name : 'l2' , 'location' : nashik , parentLocation : Maharashstra},
{id : 3 name : 'l3' , 'location' : mumbai , parentLocation : Maharashstra},
{id : 4 name : 'l4' , 'location' : Maharashstra , parentLocation : India},
{id : 5 name : 'l5' , 'location' : India , parentLocation : null}
]
Is any query we throw and get immediate node of location using above data.
Example.
When I said India it should be return
India
|---Maharashtra
|---Pune
|---..
|---Nashik
|---Mumbai
Thank you
Using Aggregation framework we can get this desired result.
The below query gives us the result and in this query I have used $lookup, $match, $project
db.location.aggregate([
{
$lookup: {
from: "location",
localField: "location",
foreignField: "parentLocation",
as:"Result"
}
},
{$match:{ "Result": {$exists:true, $ne:[]}, parentLocation: {$ne: null} }},
{$project :{ parentLocation:1, location:1, "Result.location":1}},
{$match: {location: "Maharashstra"}}
])
Documents in my collection
{ "_id" : ObjectId("5b83e4860c35ef57411a575b"), "id" : 1, "name" : "l1", "location" : "pune", "parentLocation" : "Maharashstra" }
{ "_id" : ObjectId("5b83e4860c35ef57411a575c"), "id" : 2, "name" : "l2", "location" : "nashik", "parentLocation" : "Maharashstra" }
{ "_id" : ObjectId("5b83e4860c35ef57411a575d"), "id" : 3, "name" : "l3", "location" : "mumbai", "parentLocation" : "Maharashstra" }
{ "_id" : ObjectId("5b83e4860c35ef57411a575e"), "id" : 4, "name" : "l4", "location" : "Maharashstra", "parentLocation" : "India" }
{ "_id" : ObjectId("5b83e4860c35ef57411a575f"), "id" : 5, "name" : "l5", "location" : "India", "parentLocation" : null }
{ "_id" : ObjectId("5b83fec90c35ef57411a5760"), "id" : 6, "name" : "l6", "location" : "Chennai", "parentLocation" : "Tamilnadu" }
{ "_id" : ObjectId("5b83fec90c35ef57411a5761"), "id" : 7, "name" : "l7", "location" : "Trichy", "parentLocation" : "Tamilnadu" }
{ "_id" : ObjectId("5b83fec90c35ef57411a5762"), "id" : 8, "name" : "l8", "location" : "Alapuzha", "parentLocation" : "Kerala" }
{ "_id" : ObjectId("5b83fec90c35ef57411a5763"), "id" : 9, "name" : "l9", "location" : "Kerala", "parentLocation" : "India" }
{ "_id" : ObjectId("5b83fec90c35ef57411a5764"), "id" : 10, "name" : "l10", "location" : "Tamilnadu", "parentLocation" : "India" }
After executing the above query, the result is
{
"_id" : ObjectId("5b83e4860c35ef57411a575e"),
"location" : "Maharashstra",
"parentLocation" : "India",
"Result" : [
{
"location" : "pune"
},
{
"location" : "nashik"
},
{
"location" : "mumbai"
}
]
}
If we cut down the last $match in our query, then it will return the complete the grouping of states.
db.location.aggregate([
{
$lookup: {
from: "location",
localField: "location",
foreignField: "parentLocation",
as:"Result"
}
},
{$match:{ "Result": {$exists:true, $ne:[]}, parentLocation: {$ne: null} }},
{$project :{ parentLocation:1, location:1, "Result.location":1}}
])
The result of the above query is
{
"_id" : ObjectId("5b83e4860c35ef57411a575e"),
"location" : "Maharashstra",
"parentLocation" : "India",
"Result" : [
{
"location" : "pune"
},
{
"location" : "nashik"
},
{
"location" : "mumbai"
}
]
}
{
"_id" : ObjectId("5b83fec90c35ef57411a5763"),
"location" : "Kerala",
"parentLocation" : "India",
"Result" : [
{
"location" : "Alapuzha"
}
]
}
{
"_id" : ObjectId("5b83fec90c35ef57411a5764"),
"location" : "Tamilnadu",
"parentLocation" : "India",
"Result" : [
{
"location" : "Chennai"
},
{
"location" : "Trichy"
}
]
}

Fetch Unique Document in Mongodb?

Sample Data:
{"_id" : ObjectId("58bd10e4ff1743c527754160"),
"data" : [
{
"No" : "70",
"Type" : "82",
"Device" : "01",
"timestamp" : "2017-03-06 13:00:32"
}]
},
{"_id" : ObjectId("58bd10sdfe4ff1743csdf0754"),
"data" : [
{
"No" : "75",
"Type" : "22",
"Device" : "02",
"timestamp" : "2017-03-06 13:00:32"
}]
}
I have some document which having same timestamp,so I want to find only unique document on the basis of timestamp.
I have done distinct of timestamp but I want full document.
desired Output:
If same timestamp is there I want only One document.
You will only get one output if you run this query.
db.getCollection('tests').aggregate([{$match:{"data.timestamp":"2017-03-06 13:00:32"}},{$limit:1}])
Solution 1:
db.your_collection.aggregate([
{
$group:{
_id:"$data.timestamp",
data:{
$first:"$data"
}
}
}
])
This will give you following :
{ "_id" : [ "2017-03-06 13:00:32" ], "data" : [ { "No" : "70", "Type" : "82", "Device" : "01", "timestamp" : "2017-03-06 13:00:32" }, { "No" : "10", "Type" : "20", "Device" : "01", "timestamp" : "2018-02-04 10:00:00" } ] }
Solution 2 :
db.your_collection.aggregate([
{ $unwind : '$data'},
{ $group : {
_id : '$data.timestamp',
'No': { $first : '$data.No'},
'Type': { $first : '$data.Type'},
'Device': { $first : '$data.Device'},
'timestamp': { $first : '$data.timestamp'},
}
}
]);
This will give you following :
[
{ "_id" : "2017-03-06 13:00:32", "No" : "70", "Type" : "82", "Device" : "01", "timestamp" : "2017-03-06 13:00:32" },
{ "_id" : "2018-02-04 10:00:00", "No" : "10", "Type" : "20", "Device" : "01", "timestamp" : "2018-02-04 10:00:00" },
]

Query a collection for the latest unique object

Question: Lets say I have the following objects in a collection:
How would I return one record per "product_id" and only the one with the highest "version" number? And is this possible to do within mongoose?
{
"_id" : ObjectId("54f765564b10883c1800002a"),
"total_invoice_fob_case" : 86.70999999999999,
"status" : "Draft",
"discount" : "3.40",
"effective_date" : ISODate("2013-08-01T06:00:00.000Z"),
"version" : 2,
"controlstate" : "AB",
"controlstate_id" : ObjectId("54d510e9e3d793f581b6bb27"),
"product" : "Product A",
"product_id" : ObjectId("54f75b5e4b1088801a000627"),
"size" : "1.75LTR",
"size_id" : ObjectId("5418a3dd750b4294c2cb3a47"),
"vendor" : "BEAM SUNTORY",
"vendor_id" : ObjectId("54ef5aa74b1088781b000169"),
"product_state_code" : "123",
"net_fob_cost" : 86.70999999999999,
"change_reason" : [
"Other"
],
"submitted" : {
"submitted_date" : ISODate("2014-05-16T06:00:00.000Z")
}
},
{
"_id" : ObjectId("54f765564b10883c1800002b"),
"total_invoice_fob_case" : 86.70999999999999,
"status" : "Draft",
"discount" : "4.40",
"effective_date" : ISODate("2013-08-01T06:00:00.000Z"),
"version" : 3,
"controlstate" : "AB",
"controlstate_id" : ObjectId("54d510e9e3d793f581b6bb27"),
"product" : "Product A",
"product_id" : ObjectId("54f75b5e4b1088801a000627"),
"size" : "1.75LTR",
"size_id" : ObjectId("5418a3dd750b4294c2cb3a47"),
"vendor" : "BEAM SUNTORY",
"vendor_id" : ObjectId("54ef5aa74b1088781b000169"),
"product_state_code" : "123",
"net_fob_cost" : 86.70999999999999,
"change_reason" : [
"Other"
],
"submitted" : {
"submitted_date" : ISODate("2014-05-16T06:00:00.000Z")
}
},
{
"_id" : ObjectId("54f765564b10883c1800002c"),
"total_invoice_fob_case" : 86.70999999999999,
"status" : "Draft",
"discount" : "3.40",
"effective_date" : ISODate("2013-08-01T06:00:00.000Z"),
"version" : 2,
"controlstate" : "AB",
"controlstate_id" : ObjectId("54d510e9e3d793f581b6bb27"),
"product" : "Product B",
"product_id" : ObjectId("54f75b5e4b1088801a000628"),
"size" : "1.75LTR",
"size_id" : ObjectId("5418a3dd750b4294c2cb3a47"),
"vendor" : "BEAM SUNTORY",
"vendor_id" : ObjectId("54ef5aa74b1088781b000169"),
"product_state_code" : "123",
"net_fob_cost" : 86.70999999999999,
"change_reason" : [
"Other"
],
"submitted" : {
"submitted_date" : ISODate("2014-05-16T06:00:00.000Z")
}
}
Sounds like a job for Mongo's aggregation framework. You can extrapolate from this example how to approach the problem.
Update: To retrieve one per product_id with the highest version you would need to also use $first:
db.products.aggregate([
{$sort: {product_id: 1, version: -1}}, // sort first so that $first pulls the correct record
{$group: {
_id: {product_id: '$product_id'}, // group by the product_id
product: {$first: $$ROOT} // only return the first document per group
}}
]);
You need an aggregation pipeline that first sorts the documents in the collection by version number descending using a $sort pipeline stage, then groups the ordered documents by product_id using the $group operator. Within the grouping use the $first operator on $$ROOT to return the first document in the sorted group:
var pipeline = [
{
"$sort": { "version": -1 }
},
{
"$group": {
"_id": "$product_id",
"value": {
"$first": "$$ROOT"
}
}
},
{
"$project": {
"_id": 0,
"product_id": "$_id",
"status": "$value.status",
"version": "$value.version",
"product" : "$value.product"
}
}
];
// Mongoose aggregation
Model.aggregate(pipeline, function (err, res) {
if (err) return handleError(err);
console.log(res); //
});
Console Output:
[
{
"product_id" : ObjectId("54f75b5e4b1088801a000628"),
"status" : "Draft",
"version" : 2,
"product" : "Product B"
},
{
"product_id" : ObjectId("54f75b5e4b1088801a000627"),
"status" : "Draft",
"version" : 3,
"product" : "Product A"
}
]
-- UPDATE --
To project the full document, replace the $project pipeline with the following:
{
"$project": {
"_id": 0,
"product": "$value"
}
}
Output:
/* 1 */
{
"result" : [
{
"product" : {
"_id" : ObjectId("54f765564b10883c1800002c"),
"total_invoice_fob_case" : 86.7099999999999940,
"status" : "Draft",
"discount" : "3.40",
"effective_date" : ISODate("2013-08-01T06:00:00.000Z"),
"version" : 2,
"controlstate" : "AB",
"controlstate_id" : ObjectId("54d510e9e3d793f581b6bb27"),
"product" : "Product B",
"product_id" : ObjectId("54f75b5e4b1088801a000628"),
"size" : "1.75LTR",
"size_id" : ObjectId("5418a3dd750b4294c2cb3a47"),
"vendor" : "BEAM SUNTORY",
"vendor_id" : ObjectId("54ef5aa74b1088781b000169"),
"product_state_code" : "123",
"net_fob_cost" : 86.7099999999999940,
"change_reason" : [
"Other"
],
"submitted" : {
"submitted_date" : ISODate("2014-05-16T06:00:00.000Z")
}
}
},
{
"product" : {
"_id" : ObjectId("54f765564b10883c1800002b"),
"total_invoice_fob_case" : 86.7099999999999940,
"status" : "Draft",
"discount" : "4.40",
"effective_date" : ISODate("2013-08-01T06:00:00.000Z"),
"version" : 3,
"controlstate" : "AB",
"controlstate_id" : ObjectId("54d510e9e3d793f581b6bb27"),
"product" : "Product A",
"product_id" : ObjectId("54f75b5e4b1088801a000627"),
"size" : "1.75LTR",
"size_id" : ObjectId("5418a3dd750b4294c2cb3a47"),
"vendor" : "BEAM SUNTORY",
"vendor_id" : ObjectId("54ef5aa74b1088781b000169"),
"product_state_code" : "123",
"net_fob_cost" : 86.7099999999999940,
"change_reason" : [
"Other"
],
"submitted" : {
"submitted_date" : ISODate("2014-05-16T06:00:00.000Z")
}
}
}
],
"ok" : 1
}

how to use aggregation of mongodb

From the data as given below, I want to sum all Values fields.
Please let me know how can I do it using aggregation functionality of mongodb.
{"MetricRecord":
{ "SchemaVersion" : "0.12",
"Product": {
"ProductName" : "abc",
"ProductVersion": "7.5.0.1" ,
"ProductId" : "1234567890ABDFGH12345",
"InstanceId" : "12345BA32",
"InstanceName" : "1234SS123",
"SystemId" : "somehost.com"
},
"Tenant" : {
"CustomerId" : "222-555-124",
"ServiceCode": "xyzxyzxyz12345yyy"
},
"Metrics" : [
{
"ReportType" :[
{ "report" : "billing" },
],
"LogTime" : "2013-12-08T12:34:56:01Z" ,
"Type" : "AuthorizedUsers",
"SubType" : "registered",
"Value" : "125",
"UnitOfMeasure": "USD",
"Period" : {
"StartTime" : "2013-12-07T00:00:00:01Z",
"EndTime" : "2013-12-08T00:00:00:01Z"
}
},
{
"ReportType" :[
{ "report" : "billing" }
],
"LogTime" : "2013-12-08T12:34:56:01Z" ,
"Type" : "NumberOfTickets",
"SubType" : "resolved",
"Value" : "430",
"UnitOfMeasure": "USD",
"Period" : {
"StartTime" : "2013-12-07T00:00:00:01Z",
"EndTime" : "2013-12-08T00:00:00:01Z"
}
}
]
}
}
So, results which I expect from summation of values is 430+125 i.e. 555
Your document contains string value for MetricRecord.Metrics[index].Value field and i am not sure why are you trying to sum up the string values. if it is a typo and your document contains numerical values for MetricRecord.Metrics[index].Value field then you can try the following query
db.metrics.aggregate([
{$unwind:"$MetricRecord.Metrics"},
{$group:{_id:"$_id",sum:{$sum:"$MetricRecord.Metrics.Value"}}}
])
In the above document posted, if your value field is like
MetricRecord.Metrics[0].Value is 125(not "125")
MetricRecord.Metrics[1].Value is 430(not "430")
you will get the following output
{
"result" : [
{
"_id" : ObjectId("xxxxxxxxxxxxxxxxxxxxxxxx"),
"sum" : 555
}
],
"ok" : 1
}
The above sample query is composed assuming you have the default mongodb "_id" field and you are using a metrics collection. You have to manipulate the query as per you requirements.