how to use aggregation of mongodb - 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.

Related

Updating two level sub-document which is list in mongoDB?

I have a hotel collection whose one of the document looks like this -
{
"_id" : "HOTEL_1",
"name" : "Decent hotel",
"chainId" : "CHN123",
"rooms" : [
{
"id" : "ROM1",
"name" : "decent rooms",
"ratePlans" : [
{
"ratePlanId" : "RPNB1191989873C2G",
"status" : "INACTIVE",
"marginPart" : {
"marginType" : "PERCENTAGE",
"margin" : "32"
}
},
{
"ratePlanId" : "RPNE0992HBG6I0GE8",
"status" : "INACTIVE",
"marginPart" : {
"marginType" : "PERCENTAGE",
"margin" : "32"
}
}
]
},
{
"id" : "ROM2",
"name" : "another decent rooms"
"ratePlans" : []
}
]
}
I need to update status as ACTIVE of all the rate plans of all the rooms with a certain condition like chainId.
I tried with this but failed -
db.hotel.updateMany({ "chainId" : "CHN_123"},{$set : {"rooms.$ratePlans.$status" : "ACTIVE" }});
I also want to update margin as common value say 50% to all such rates.
Instead of updateMany try the below query
db.hotel.update({ "chainId" : "CHN_123"},{$set : {"rooms.$ratePlans.$status" : "ACTIVE" }},{multi:true,upsert:false},function(err,doc){
console.log(doc)
});
It works always!!

MongoDB $lookup on array of object

I have 2 collections structured as below. I have tried $lookup to get the result but I am not getting any result because of my local and foreign fields are in array of object.
Below is my structure:
{
"_id" : ObjectId("5795a3531d3f3afc19caefef"),
"name" : "category1",
"updatedAt" : "1469431592786",
"resources" : [
{
"_id" : ObjectId("5791be003fa3bedc15d3adde"),
"title" : "resource1",
"availability" : false
},
{
"_id" : ObjectId("5795a3771d3f3afc19caeff0"),
"title" : "resource2",
"availability" : true
}
]
}
Above "categories" schema have resources array of object. this resource _id is stored in bookings collection in following way:
"booking":
{
"_id" : ObjectId("57960aa8000ca7a46b7ef683"),
"name" : "1469491200000",
"__v" : 0,
"schedule" : [
{
"resourceId" : ObjectId("5791be003fa3bedc15d3adde"),
"userId" : ObjectId("5791be003fa3bedc15d3adcve"),
"title" : "grofep",
"_id" : ObjectId("57960aa8f9f9951c1fc923b1")
},
{
"resourceId" : ObjectId("5791be003fa3bedc15d3bddz"),
"userId" : ObjectId("5791be003fa3bedc15d3adcve"),
"title" : "mr3",
"_id" : ObjectId("57960aa8f9f9951c1fc923b2")
},
{
"resourceId" : ObjectId("5791be003fa3bedc15d3adde"),
"userId" : ObjectId("5791be003fa3bedc15d3adcve"),
"title" : "grofep23",
"_id" : ObjectId("57960aa8f9f9951c1fc923b3")
}
]
}
Now I want to get all the schedule of booking collection with their resource information.I want to fetch resources from categories table on the basis of booking schedule.
Desired output:
[
{
"name" : "1469491200000",
"resourceId" : ObjectId("5791be003fa3bedc15d3adde"),
"resourceTitle":"title",
"availability":false,
"bookings": [
{
"userId" : ObjectId("5791be003fa3bedc15d3adcve"),
"title" : "grofep",
"_id" : ObjectId("57960aa8f9f9951c1fc923b1")
},
{
"userId" : ObjectId("5791be003fa3bedc15d3adcve"),
"title" : "grofep23",
"_id" : ObjectId("57960aa8f9f9951c1fc923b3")
}
]
},
{
"name" : "1469491200000",
"resourceId" : ObjectId("5791be003fa3bedc15d3bddz"),
"resourceTitle":"mr3",
"availability":false,
"bookings": [
{
"userId" : ObjectId("5791be003fa3bedc15d3adcve"),
"title" : "mr3",
"_id" : ObjectId("57960aa8f9f9951c1fc923b2")
}
]
}
]
Help me to get this desired result.
Thanks.

MongoDB and aggragate the embeded document

I am new to mongoDB and I came across a problem. The data was imported according to official doc.
As you can see, each of restaurant has a grades array and the nested document contains a score field. What I want to do is according to the average score of each restaurant's grades and retrive the restaurant that has the top average score. This may need to use mongoDB's aggregate method but the document doesn't cover the nested document situation and I googled but without a result. There's a similar question on this site but it's not so clear.
[
{ "_id" : ObjectId("56a9f39cae1902590811dffc"),
"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" },
...
]
Using the mongo shell, try the below , change "collecttionname" to the name of your your restaurant collections
db.collectionname.aggregate( { '$unwind' : '$grades' } , { '$group' : { '_id' : '$_id' , 'average' : { $avg : '$grades.score' } } } , { '$sort' : { 'average' : -1 } } , { '$limit' : 1 } )

view of query in mongodb

I have a collection ,this is one of it's docs :
{
"_id" : 1 ,
"first_name" : "john",
"phone" : [
{
"type" : "mobile",
"number" : "9151112233"
},
{
"type" : "home",
"city_code" : 51,
"number" : "55251544"
},
{
"type" : "mobile",
"number" : "9152425125"
}
]
}
I'm searching for "phones" that contain type "mobile" and show them.
I need something like this :
{
"number" : "9151112233",
"number" : "9152425125"
}
I write this query for that :
db.main.find({ _id : 1 , 'phone.type' : "mobile" },{'phone.number' : true , _id : false}).forEach(printjson)
I want to show only numbers that their types are mobile but this query show all to numbers because this single doc contain others too.
How can I fix it?
I'd use the aggregation framework along with the $unwind, $match and $project commands. This:
db.main.aggregate({$unwind:"$phone"},{$match:{"phone.type":"mobile"}},{$project:{"phone.number":1,"_id":0}})
produces this output:
{ "phone" : { "number" : "9151112233" } }
{ "phone" : { "number" : "9152425125" } }
which only matches the mobile numbers.
http://docs.mongodb.org/manual/aggregation/

How to get exact document result from key value type of embedded documents

Let say I have this kind of document structured, the attributes field will be the embedded document
and I've already indexed the attributes.key and attributes.value
1-------------------------------------------------------------------------------------
{
"_id" : ObjectId( "5191d8e5d00560402e000001" ),
"attributes" : [
{ "key" : "pobox","value" : "QaKUWo" },
{ "key" : "city", "value" : "CBDRip" },
{ "key" : "address","value" : "zmycAa" } ],
"email" : "FWAUdl_2#email.com",
"firstname" : "FWAUdl_2"
}
2-------------------------------------------------------------------------------------
{
"_id" : ObjectId( "5191d8e7d00560402e000055" ),
"attributes" : [
{ "key" : "pobox", "value" : "sNFriy" },
{ "key" : "city", "value" : "JPdVrI" },
{ "key" : "address", "value" : "phOluW" } ],
"email" : "hqYNWH_86#email.com",
"firstname" : "hqYNWH_86"
}
My problem is how to get exact document when querying based only on the attributes field,
db.app.find({ attributes.key:address , attributes.value:/.*uw.*/i })
The query result is not as I expected, it should result only the 2nd document only without the 1st document.
I know that I put regex on the attributes.value, I was expecting that it only check for attributes.key that have address value.
And what if I want to filter another key, such like,
db.app.find({ attributes.key:address , attributes.value:/.*uw.*/i , attributes.key:city , attributes.value:/.*ri.*/i })
Any opinion will be helpful guys.
Thx.
I guess you need $elemMatch ( http://docs.mongodb.org/manual/reference/operator/elemMatch/ )
db.test123.find({ attributes : { $elemMatch : { 'key':"address" , 'value':/.*uw.*/i } } }).pretty()
{
"_id" : ObjectId("5191d8e7d00560402e000055"),
"attributes" : [
{
"key" : "pobox",
"value" : "sNFriy"
},
{
"key" : "city",
"value" : "JPdVrI"
},
{
"key" : "address",
"value" : "phOluW"
}
],
"email" : "hqYNWH_86#email.com",
"firstname" : "hqYNWH_86"
}
Just investigated a little and figured out following. The following uses the index mentioned below. You can do a explain() on the find() to check more index usage details
db.testing.getIndexKeys()
[ { "_id" : 1 }, { "attributes.key" : 1, "attributes.value" : 1 } ]
test:Mongo > db.testing.find({$and : [ { attributes : {$elemMatch : {key : 'address', value : /.*uw.*/i }} }, { attributes : {$elemMatch : {key : 'city', value : /.*ri.*/i }} }] }).pretty()
{
"_id" : ObjectId("5191d8e7d00560402e000055"),
"attributes" : [
{
"key" : "pobox",
"value" : "sNFriy"
},
{
"key" : "city",
"value" : "JPdVrI"
},
{
"key" : "address",
"value" : "phOluW"
}
],
"email" : "hqYNWH_86#email.com",
"firstname" : "hqYNWH_86"
}