Mongodb $unwind for mongoid embedded document - mongodb

following is an example of schema I have or trying to query to
{
"_id" : ObjectId("5139f9468efdd10e44000024"),
"name" : "Test Test",
"account_activities" : [
{
"_id" : ObjectId("5139f9468efdd10e44000025"),
"activity_id" : ObjectId("5139f6118efdd10e4400000e"),
"allowance" : 100,
"base_rate" : {
"cents" : 80,
"currency_iso" : "USD"
},
"excess_rate" : {
"cents" : 90,
"currency_iso" : "USD"
},
"quota" : 100,
"taxable" : true,
"description" : "",
"sm" : 1,
"updated_at" : ISODate("2015-07-24T16:18:50.942Z")
}
],
"account_number" : "D-061-5556",
"active" : false,
"balance" : {
"cents" : 0,
"currency_iso" : "USD"
},
}
On running an $unwind I get nothing, is there something I am doing wrong..?
db.accounts.aggregate([{$unwind: "$account_activities"}, {$project: {_id: 0, name: 1, base_rate: 1}}])
I am using mongo shell version 2.6.12

base_rate is still under account_activities. So you have to project it as below
db.accounts.aggregate([
{$unwind: "$account_activities"},
{$project: {
_id: 0,
name: 1,
'account_activities.base_rate': 1
}}
])

Related

In $project, can we replace the _id and make the _id value as 1, 2, 3...n for all documents in array

Using project in mongodb, when we get the output as array, can we replace
the _id and make the _id value as 1, 2, 3...n
for all documents in array.
'project' is giving below output:
query:
db.premiumChange.aggregate([
{'$unwind': '$history'}
,{'$match': {
'history.startDate': {'$gte': ISODate('2018-01-21T11:13:14.000Z')}
,'history.endDate': {'$lte':ISODate('2018-02-20T11:13:14.000Z')}
}}
,{'$facet':{'APTCChange':[{'$match': {'history.APTCChange': {'$gt': 10}}}
,{'$limit':8}
,{ $project: {
APTCChange: '$history.APTCChange'}}]
,"PremChange": [ {$match:{"history.APTCChange":{"$gt":10}}}
,{'$limit':1}
,{ $project: {
APTCChange: '$history.APTCChange'}}]
,"MbrRespChg": [ {$match:{"history.MbrRespChg":{"$gt":10}}}
,{'$limit':1}
,{ $project: {
APTCChange: '$history.APTCChange'}}, {'$limit':1}] } }
])
above query is giving below result with automatically added _id that documents in the array.
but as per my requirement, every document in the array should have _id as 0,1,2..n.
{
"APTCChange" : [
{
"_id" : "HCCIDM1234567A",
"APTCChange" : 1200,
},
{
"_id" : "HCCIDM1234567B",
"APTCChange" : 1200,
}],
"PremChange" : [
{
"_id" : "HCCIDM1234567A",
"APTCChange" : 1200,
},
{
"_id" : "HCCIDM1234567B",
"APTCChange" : 1200,
}],
"MbrRespChg" : [
{
"_id" : "HCCIDM1234567A",
"APTCChange" : 1200,
},
{
"_id" : "HCCIDM1234567B",
"APTCChange" : 1200,
}]}
instead i need like below:
{
"APTCChange" : [
{
"_id" : 0,
"APTCChange" : 1200,
},
{
"_id" : 1,
"APTCChange" : 1200,
}],
"PremChange" : [
{
"_id" : 3,
"APTCChange" : 1200,
},
{
"_id" : 4,
"APTCChange" : 1200,
}],
"MbrRespChg" : [
{
"_id" : 5,
"APTCChange" : 1200,
},
{
"_id" : 6,
"APTCChange" : 1200,
}]}
try this aggregation, we calculate _id by getting the $size of previous arrays summing with current array index of element
pipeline
db.col.aggregate([
{$project : {
APTCChange : {
$map : {
input : "$APTCChange",
as : "a",
in : {
_id : {$indexOfArray : ["$APTCChange._id", "$$a._id"]},
APTCChange : "$$a.APTCChange"
}
}
},
PremChange : {
$map : {
input : "$PremChange",
as : "a",
in : {
_id : {$add : [{$indexOfArray : ["$PremChange._id", "$$a._id"]}, {$size : "$APTCChange"}]},
APTCChange : "$$a.APTCChange"
}
}
},
MbrRespChg : {
$map : {
input : "$MbrRespChg",
as : "a",
in : {
_id : {$add : [{$indexOfArray : ["$MbrRespChg._id", "$$a._id"]}, {$size : "$APTCChange"}, {$size : "$MbrRespChg"}]},
APTCChange : "$$a.APTCChange"
}
}
}
}}
]).pretty()
result
{
"_id" : ObjectId("5a9064a2996e36f33cd29dd0"),
"APTCChange" : [
{
"_id" : 0,
"APTCChange" : 1200
},
{
"_id" : 1,
"APTCChange" : 1200
}
],
"PremChange" : [
{
"_id" : 2,
"APTCChange" : 1200
},
{
"_id" : 3,
"APTCChange" : 1200
}
],
"MbrRespChg" : [
{
"_id" : 4,
"APTCChange" : 1200
},
{
"_id" : 5,
"APTCChange" : 1200
}
]
}
>

Query to group distinct values and show sum of array values in mongodb

I wanted to group by cart.name and find the sum of cart.qty in mongodb. Below is sample document
{
"_id" : ObjectId("581323379ae5e607645cb485"),
"cust" : {
"name" : "Customer 1",
"dob" : "09/04/1989",
"mob" : 999999999,
"loc" : "Karimangalam",
"aadhar" : {
}
},
"cart" : [
{
"name" : "Casual Shirt",
"qty" : 1,
"mrp" : 585,
"discperc" : 10,
"fit" : null,
"size" : "L"
},
{
"name" : "Casual Shirt",
"qty" : 1,
"mrp" : 500,
"discperc" : 0,
"fit" : null,
"size" : "L"
},
{
"name" : "Cotton Pant",
"qty" : 1,
"mrp" : 850,
"discperc" : 0,
"fit" : null,
"size" : "34"
},
{
"name" : "Cotton Pant",
"qty" : 1,
"mrp" : 1051,
"discperc" : 10,
"fit" : null,
"size" : "34"
}
],
"summary" : {
"bill" : 2822.4,
"qty" : 4,
"mrp" : 2986,
"received" : "2800",
"balance" : -22.40000000000009
},
"createdAt" : ISODate("2016-10-28T10:06:47.367Z"),
"updatedAt" : ISODate("2016-10-28T10:06:47.367Z")
}
There are many document like this. I want the output as below distinct product name (cart.name) and its total qty
{Casual Shirt , 30},
{Cotton Pant , 10},
{T-Shirt , 15},
{Lower , 12}
Here is my query trying to group by cart.name and sum qty
db.order.aggregate( [
{ $unwind: "$cart" },
{ $group: {
_id: "$cart.name",
totalQTY: { $sum:"$cart.qty"},
count: { $sum: 1 }
}
}
] )
but it displays wrong totalQty values for each product name. I checked manually.
Please give me the correct query.
> db.collection.aggregate([
... { $unwind: "$cart" },
... { $group: { "_id": "$cart.name", totalQTY: { $sum: "$cart.qty" }, count: { $sum: 1 } } }
... ])
I get the following result:
{ "_id" : "Cotton Pant", "totalQTY" : 2, "count" : 2 }
{ "_id" : "Casual Shirt", "totalQTY" : 11, "count" : 2 }
I'm not sure what you're looking for, it looks like your aggregation pipeline is correct. (Note I changed the Casual Shirt Quantity to be 10 and 1 respectively)

mongodb unwind array nested inside an array of documents

In MongoDB, I need to be able to unwind nested an array in a document inside an array inside the main document.
{
"_id" : ObjectId("5808d700536d1a3d69f4cf51"),
"last_name" : "Maity",
"xiith_mark" : 58,
"id" : "3539488",
"first_name" : "Harshavardhan",
"course_name" : "BE/B.Tech",
"institute_name_string" : "Abhayapuri College, P.O. Abhayapuri",
"profile_percentage" : 45,
"xiith_mark_type" : "Percentage",
"xth_mark_type" : "Percentage",
"date_of_birth" : "14-April-1993",
"xth_mark" : 30,
"last_login" : 1470827224,
"percentage" : 55,
"job_details" : [
{
"status" : NumberLong(6),
"applied_date" : NumberLong(1470831441),
"job_id" : NumberLong(92928),
"contact_viwed_status" : 0,
"label_name" : [
"shortlisted",
"rejected"
],
"questionnaire_status" : 0,
"batch_id" : NumberLong(6),
"call_letter" : NumberLong(812)
},
{
"status" : NumberLong(6),
"applied_date" : NumberLong(1470831441),
"job_id" : NumberLong(92928),
"contact_viwed_status" : 0,
"label_name" : [
"shortlisted",
"rejected"
],
"questionnaire_status" : 0,
"batch_id" : NumberLong(6),
"call_letter" : NumberLong(812)
}
],
"branch_name" : "Applied Electronics",
"candidate_state_name" : "West Bengal",
"candidate_city_name_string" : "Kolkata",
"10" : 10,
"12" : 12,
"skills" : "",
"gender" : "Male",
"fw_id" : "FW15884830",
"cgpa" : 0,
"picture_path" : "",
"hq_passout_year" : 2019
}
Based on the record above I need to count the job labels (job_details.label_name).
I have tried the following query:
db.response.aggregate(
{"$match":type_match},
{"$unwind": "$job_details" },
{"$group":
{
"_id":"$job_details.label_name",
"count": {"$sum": 1 }
}
}
])
The output is:
{
"count": 2,
"_id": [
"shortlisted",
"rejected"
]
}
But I want the output to be:
[
{
"count": 1,
"_id": "shortlisted"
},
{
"count": 1,
"_id": "rejected"
}
]
How can I get this output?
In unwind stage, field should be an array field. If not array field, it treats it as array of 1 element.
From the docs:
Changed in version 3.2: $unwind stage no longer errors on non-array operands. If the operand does not resolve to an array but is not missing, null, or an empty array, $unwind treats the operand as a single element array.
Answer to your query:
db.response.aggregate([
{
$project:
{
"job_details.label_name":1,
_id:0
}
},
{
$unwind:"$job_details.label_name"
},
{
$group:
{
_id:"$job_details.label_name",
count:{$sum:1}
}
}
])
Refer Shell Output

MongoDB aggregate $match and $group with $sum

i have a collection with documents like this:
{
"Company" : "4433",
"Descripcion" : "trabajo",
"Referencia" : "11817",
"HoraImportado" : "15:54",
"ImportedOd" : "2014-05-20T13:54:28.493Z",
"Items" : [],
"Notes" : [
{
"_id" : ObjectId("537b5ea4c61b1d1743f43420"),
"NoteDateTime" : "2014-05-20T13:54:44.418Z",
"Description" : "nota",
"IsForTechnician" : true,
"Username" : "admin"
},
{
"_id" : ObjectId("537c4a549e956f77ab8c7c38"),
"NoteDateTime" : ISODate("2014-05-21T06:40:20.299Z"),
"Description" : "ok",
"IsForTechnician" : true,
"Username" : "admin"
}
],
"OrderState" : "Review",
"SiniestroDe" : "Emergencia",
"Technicians" : [
{
"TechnicianId" : ObjectId("53465f9d519c94680327965d"),
"Name" : "Administrator",
"AssignedOn" : ISODate("2014-05-20T13:54:44.373Z"),
"RemovedOn" : null
}
],
"TechniciansHistory" : [
{
"TechnicianId" : ObjectId("53465f9d519c94680327965d"),
"Name" : "Administrator",
"AssignedOn" : ISODate("2014-05-20T13:54:44.373Z"),
"RemovedOn" : null
},
{
"Name" : "Nuevo",
"AssignedOn" : ISODate("2014-05-20T13:54:44.373Z"),
"RemovedOn" : null,
"TechnicianId" : ObjectId("5383577a994be8b9a9e3f01e")
}
],
"Telefonos" : "615554006",
"_id" : ObjectId("537b5ea4c61b1d1743f4341f"),
"works" : [
{
"code" : "A001",
"name" : "Cambiar bombilla",
"orderId" : "537b5ea4c61b1d1743f4341f",
"price" : "11",
"ID" : 33,
"lazyLoaded" : true,
"status" : 0,
"Date" : ISODate("2014-05-21T06:40:20.299Z"),
"TechnicianId" : "53465f9d519c94680327965d",
"_id" : ObjectId("537c4a549e956f77ab8c7c39")
},
{
"code" : "A001",
"name" : "Cambiar bombilla",
"orderId" : "537b5ea4c61b1d1743f4341f",
"price" : "11",
"ID" : 34,
"lazyLoaded" : true,
"status" : 0,
"Date" : ISODate("2014-05-21T06:40:20.299Z"),
"TechnicianId" : "53465f9d519c94680327965d",
"_id" : ObjectId("537c4a549e956f77ab8c7c3a")
}
]
}
Now i want to get the works for a selected TechnicianId array, group by TechnicianId and get the sum of the works.price for each technician.+
I try with this:
db.orders.aggregate([
{ $match: { 'works.TechnicianId': {$in:['53465f9d519c94680327965d']}}},
{ $group: { _id: "$works.TechnicianId",total:{$sum:'$works.price'}}},
])
And this is the result:
{
"result" : [
{
"_id" : [
"53465f9d519c94680327965d",
"53465f9d519c94680327965d"
],
"total" : 0
}
],
"ok" : 1
}
The total its the $sum but its 0 but should be 44.
Try adding unwind,
db.orders.aggregate([
{ $match: { 'works.TechnicianId': {$in:['53465f9d519c94680327965d']}}},
{ $unwind: "$works" },
{ $group: { _id: "$works.TechnicianId",total:{$sum:'$works.price'}}},
])
Look here for more info : http://docs.mongodb.org/manual/reference/operator/aggregation/unwind/
The price value is a string. $sum only operates on Numbers.
I've checked this by running the following:
db.foo.insert({"cost": "1"})
db.foo.insert({"cost": "2"})
db.foo.insert({"cost": "3"})
db.foo.insert({"cost": 4})
db.foo.insert({"cost": 5})
db.foo.aggregate([{$group: {_id: null, cost: {$sum: "$cost"}}}])
{ "result" : [ { "_id" : null, "cost" : 9 } ], "ok" : 1 }
According to this answer, you can't cast values in normal Mongo queries, so you can't change the string to a number inline.
You should either update all values to a Number datatype or use map-reduce. I'd go for the former.
If the value is a string to prevent floating point errors, consider multiplying by 100 to store the value in cents: "10.50" --> 1050
As Lalit Agarwal indicated, you'll also need to unwind the array of works. Example of what happens if you don't:
db.bar.insert({"works": [{price: 10}]})
db.bar.insert({"works": [{price: 20}, {price: 30}]})
db.bar.insert({"works": [{price: 40}, {price: 50}]})
db.bar.aggregate([
{$group: {_id: null, total: {$sum: "$works.price"} }}
])
{ "result" : [ { "_id" : null, "total" : 0 } ], "ok" : 1 }
db.bar.aggregate([
{$unwind: "$works"},
{$group: {_id: null, total: {$sum: "$works.price"} }}
])
{ "result" : [ { "_id" : null, "total" : 150 } ], "ok" : 1 }
What $unwind does is make 5 documents out of the initial 3, all with a single value in the works field. It then groups and sums them.
db.inventory.insert(
{
item: “ABC1”,
details: {
model: “14Q3”,
manufacturer: “XYZ Company”
},
stock: [ { size: “S”, qty: 25 }, { size: “M”, qty: 50 } ],
category: “clothing”
}
)

Aggregate inside document in mongodb

I have document sales
db.sale.findOne({_id : ObjectId("52ea4dd29dbc7923107ddb97")})
{
"_id" : ObjectId("52ea4dd29dbc7923107ddb97"),
"firm" : ObjectId("52e56c009dbc794999ea5c3d"),
"patient" : {
"last" : "",
"first" : ""
},
"doc" : "",
"hospital" : "",
"discount" : 0,
"dd" : "",
"mode" : "cash",
"invoice" : "300114-undefined-1",
"items" : [
{
"bat" : "BJFE",
"narco" : 0,
"name" : "GDRNCCD",
"mrp" : 1,
"free" : 0,
"qty" : 1,
"item_discount" : 0,
"wpr" : 1,
"exp" : "1425168000000"
},
{
"bat" : "",
"narco" : 0,
"name" : "GDRN vbhjdsfb",
"mrp" : 1,
"free" : 0,
"qty" : 1,
"item_discount" : 0,
"wpr" : 0,
"exp" : "[object Object]"
},
{
"bat" : "",
"narco" : 0,
"name" : "GDRN vbhjdsfb",
"mrp" : 1,
"free" : 0,
"qty" : 1,
"item_discount" : 0,
"wpr" : 0,
"exp" : "[object Object]"
}
],
"date" : ISODate("2014-01-30T00:00:00Z"),
"mob" : "",
"email" : ""
}
How can I Aggregate total numbers if items in one field and sum up mrp *qty of all the items into one field.
I have read the mognodb aggregation but it only aggregates among group of matched documents not inside a single document. Is it possile?
{
"_id" : ObjectId("52ea4dd29dbc7923107ddb97"),
"firm" : ObjectId("52e56c009dbc794999ea5c3d"),
'total_items' : items.length,
"total" : mrp*qty of all items,
}
db.sales.aggregate(
{$unwind: "$items"},
{$project: {_id: 1,firm:1, total: {$multiply: ["$items.mrp", "$items.qty"]}}},
{$group: {_id: {"id":"$_id", firm:"$firm"}, count: {$sum:1} , total : {$sum:"$total"}}}
)
With a slight change : _id contains id and firm, you will need an extra projection to match your desired document, but I don't think it's important.
Plus, you can easily change to group by farm only
Thanks to Orid,I tried this,
db.sale.aggregate(
{ $match :{ firm :ObjectId("52e56c009dbc794999ea5c3d") } },
{$project : {day : {$dayOfMonth : '$date'},items :1,patient :1,invoice :1}},
{$match : {day: {$gte : new Date().getDate()}}},
{$unwind : "$items"},
{$project: {_id: 1,patient:1,invoice :1, total: {$multiply: ["$items.mrp", "$items.qty"]}}},
{$group: {_id: {"id":"$_id", invoice:"$invoice",patient :"$patient"}, count: {$sum:1} , total : {$sum:"$total"}}})
Result
{
"result" : [
{
"_id" : {
"id" : ObjectId("52eab6129dbc7923107ddbaf"),
"invoice" : "310114-undefined-1",
"patient" : {
"last" : "",
"first" : ""
}
},
"count" : 2,
"total" : 25
},
{
"_id" : {
"id" : ObjectId("52eab6129dbc7923107ddbb0"),
"invoice" : "310114-undefined-1",
"patient" : {
"last" : "",
"first" : ""
}
},
"count" : 1,
"total" : 1
},
{
"_id" : {
"id" : ObjectId("52eab6129dbc7923107ddbae"),
"invoice" : "310114-undefined-1",
"patient" : {
"last" : "",
"first" : ""
}
},
"count" : 2,
"total" : 5
}
],
"ok" : 1
}