How to create a root element inside a Collection in MongoDB? - mongodb

I imported this:
{
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE",
}
{
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100",
}
And i put the data inside an array like this:
{Crs:{[
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE",
}},
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100",
}},
]}}
I have this data that i importet and I would like to know how I put it inside a my Main element and modeling like this, using aggregate.
{Main: {
"_id" : ObjectId("main1"),
"Name" : "MainNAme1",
{Crs:{[
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE",
}},
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100",
}},
]}},
}}

can you try this aggregation
db.crs.aggregate(
[
{$group : {_id : null, crs : {$push : {cr : "$$ROOT"}}}},
{$addFields : {"Main._id" : "main1", "Main.name" : "MainNAme1", "Main.crs" : "$crs"}},
{$project : {_id : 0 , crs : 0}}
]
)

Related

How to model this data on MongoDB

I have this data:
{
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE",
}
{
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100",
}
And i want to model this data so it stays like this:
{Crs:{[
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE",
}},
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100",
}},
]}}
I read something about Model One-to-Many Relationships with Embedded Documents but i really dont know how it works.
https://docs.mongodb.com/manual/core/data-model-design/
use aggregation
> db.crs.aggregate(
[
{$group : {_id : null, crs : {$push : {cr : "$$ROOT"}}}},
{$project : {_id : 0}}
]
).pretty()
you can also write the result data to another collection using $out
add below as last stage in aggregate pipeline
{$out : "crs"} // create collection crs
output
> db.crs.aggregate([{$group : {_id : null, crs : {$push : {cr : "$$ROOT"}}}}, {$project : {_id : 0}}]).pretty()
{
"crs" : [
{
"cr" : {
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE"
}
},
{
"cr" : {
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100"
}
}
]
}
>
I think the documentation here should be of some help: https://docs.mongodb.com/manual/reference/operator/update/positional/#update-documents-in-an-array
And in your case it would be something similar to this:
db.nameOfCollection.updateOne(
{ _id: ObjectId('idhere'), "Crs.Cr.Number": 400 },
{ $set: { "Crs.$.Cr.DC" : "SomethingNew" } }
)
One thing here, I'm not sure you're data structure seems correct as you have an array inside an object...why not just an array, i.e.
Crs: [{...}, {...}]

Aggregate based on Array value

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

Nested conditional MongoDB query

Im having a hard time trying to run some nested queries with a conditional statement of an item inside an array.
this is how my documents looks like.
I would like to get a summary such as sum and average and alarmedCount (count every time Channels.AlarmStatus == "alarmed") of each "Channel" based on Channels.Id. I got sum and average to work but cant get the right query for alarmedCount
{
"_id" : "55df8e4cd8afa4ccer1915ee"
"location" : "1",
"Channels" : [{
"_id" : "55df8e4cdsafa4cc0d1915r1",
"ChannelId" : 1,
"Value" : 14,
"AlarmStatus" : "normal"
},
{
"_id" : "55df8e4cdsafa4cc0d1915r9",
"ChannelId" : 2,
"Value" : 20,
"AlarmStatus" : "alarmed"
},
{
"_id" : "55df8e4cdsafa4cc0d1915re",
"ChannelId" : 3,
"Value" : 10,
"AlarmStatus" : "alarmed"},
]
}
{
"_id" : "55df8e4cd8afa4ccer1915e0"
"location" : "1",
"Channels" : [{
"_id" : "55df8e4cdsafa4cc0d19159",
"ChannelId" : 1,
"Value" : 50,
"AlarmStatus" : "normal"
},
{
"_id" : "55df8e4cdsafa4cc0d1915re",
"ChannelId" : 2,
"Value" : 16,
"AlarmStatus" : "normal"
},
{
"_id" : "55df8e4cdsafa4cc0d1915g7",
"ChannelId" : 3,
"Value" : 9,
"AlarmStatus" : "alarmed"},
]
}
I got it to work to group them and show some calculations
using this aggregate
db.records.aggregate( [
{
"$unwind" : "$Channels"
},
{
"$group" : {
"_id" : "$Channels.Id",
"documentSum" : { "$sum" : "$Channels.Value" },
"documentAvg" : { "$avg" : "$Channels.Value" }
}
}
] )
the result looks like this:
{
"result" : [
{
"_id" : 1,
"documentSum" : 64,
"documentAvg" : 32
},
{
"_id" : 2,
"documentSum" : 36,
"documentAvg" : 18
},
{
"_id" : 3,
"documentSum" : 19,
"documentAvg" : 9.5
},
],
"ok" : 1.0000000000000000
}
I would like to get this type of result
{
"result" : [
{
"_id" : 1,
"documentSum" : 64,
"documentAvg" : 32,
"AlarmedCount" : 0
},
{
"_id" : 2,
"documentSum" : 36,
"documentAvg" : 18,
"AlarmedCount" : 1
},
{
"_id" : 3,
"documentSum" : 19,
"documentAvg" : 9.5,
"AlarmedCount" : 2
}
],
"ok" : 1.0000000000000000
}
Use a project-step before your group-step to convert the field AlarmedStatus to 1 or 0 depending on its value:
$project: {
"Channels.value":"$Channels.Value",
"Channels.AlarmCount":{ $cond: {
if: { $eq: ["$Channels.AlarmedStatus", "alarmed"] },
then: 1,
else: 0 }
}
}
Then sum the newly created field to get the aggregated count:
$group : {
"_id" : "$Channels.Id",
"documentSum" : { "$sum" : "$Channels.Value" },
"documentAvg" : { "$avg" : "$Channels.Value" },
"AlarmCount" : { "$sum" : "$Channels.AlarmCount" }
}

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
}

Exact Reduce function

I have a collection of the type :
{
"_id" : ObjectId("51f1fcc08188d3117c6da351"),
"cust_id" : "abc123",
"ord_date" : ISODate("2012-10-03T18:30:00Z"),
"status" : "A",
"price" : 25,
"items" : [{
"sku" : "ggg",
"qty" : 7,
"price" : 2.5
}, {
"sku" : "ppp",
"qty" : 5,
"price" : 2.5
}]
}
I want to fetch only the "items" object whose "items.qty">5 and and"items.sku"=="ggg".
I applied Map reduce:
cmd { "mapreduce" : "orders" , "map" : "function map(){var items_out={items:[]};for(i in this.items){items_out.items.push(this.items[i].sku);};emit(this._id,[items_out]);}" , "reduce" : "function reduce(key,values){return {'result':values};}" , "verbose" : true , "out" : { "replace" : "map_reduce"} , "query" : { "$where" : "return this.items.some(function(entry){return entry.qty>5})&&this.items.some(function(entry){return entry.sku=='ggg'})"}},
but I am getting all the sku values something like this:
{ "data": [ { "items": [ "ggg", "ppp" ] } ]}
Whereas it should give only ggg as this is the only value matching criteria.
Use the following command:
db.orders.aggregate(
{$unwind : "$items"},
{$match : {"items.qty": {$gt: 5 }}},
{$match : {"items.sku" : "ggg"}},
{$project : {_id:0, items:1}}
)