Using sum in Mongo - mongodb

I'm learning mongo and I have this schema below and i would like some help defining a query:
I would like to get the sum of the "entregado" fields that match this code: 151001. In this case i would get this result = 38.
Do I need to change the schema or is easy to get a query for what i want?
{
"_id": 101,
"torre": 1,
"standard": {
"mamposteria": [
{
"codigo": 311017,
"descripcion": "LADRILLO ARCILLA H-10",
"cantidad": 1080,
"um": "UN",
"entregado": 1080,
"fecha": new Date('June 10, 2013'),
"vale": [1322]
},
{
"codigo": 311021,
"descripcion": "LADRILLO ARCILLA H-7",
"cantidad": 200,
"um": "UN",
"entregado": 200,
"fecha": new Date('June 10, 2013'),
"vale": [1322]
},
{
"codigo": 151001,
"descripcion": "CEMENTO GRIS 50 KG",
"cantidad": 17,
"um": "KG",
"entregado": 17,
"fecha": new Date('June 10, 2013'),
"vale": [1322]
}
],
"mortero": [
// . . .
],
"estructura":[
// . . .
]
}
}

To get the count alone u don't need to modify your schema.
Just following the below steps can give you the count what u need. I will not give you the whole query to find the count. That makes u lazy..so will give steps to get the count...
1) use $unwind 2) use $match to find the value for code: 151001 3) use $group to $sum the values present in entregado
This should give you the count.
If you need any other help pls contact me I will help

Related

Querying MongoDB collection consisting of one document which in turn is a multi-level nested object with objects/arrays nested inside

DB collection seatsObj:
{
"product_id": 46539040,
"freeSeating": false,
"tempTransId": "1ecae165f2d86315fea19963d0ded41a",
"seatLayout": {
"colAreas": {
"Count": 2,
"intMaxSeatId": 43,
"intMinSeatId": 2,
"objArea": [
{
"AreaDesc": "EXECUTIVE",
"AreaCode": "0000000003",
"AreaNum": "1",
"HasCurrentOrder": true,
"objRow": [
{
"GridRowId": 1,
"PhyRowId": "A",
"objSeat": [
{
"GridSeatNum": 1,
"SeatStatus": "1",
"seatNumber": 1,
"seatPrice": 400,
"ID": 111
},
{
"GridSeatNum": 2,
"SeatStatus": "0",
"seatNumber": 2,
"seatPrice": 450,
"ID": 112
},
I was able to find ways to locate and update specific fields using:
seatsObj.updateOne(
{"seatLayout.colAreas.objArea.0.objRow.0.objSeat.seatPrice": 470},
{$set: {"seatLayout.colAreas.objArea.0.objRow.0.objSeat.$.ID": 888}});
but i cannot find simple way to return a specific field value from objSeat array element based on search criteria (for example: get 400 as a result of querying seatPrice for the seat with ID = 111). Could anyone give me a direction? From my initial research I have to go into crazy nested $unwind -s and $objectToArray -s, etc... Isn't there a simpler way? Thank you!!

Calculate average error via aggregation pymongo

I am trying to find the average error for predictions made n-1, n-2, ... n-5 hours before an event happens. One "row" of my data looks like this:
note: _id is the time_collected.
{'_id': 5pm,
'value_at_time_collected': 72,
'predictions': [
{'prediction': 77, 'time': 6pm},
...
{'prediction': 79, 'time': 10pm},
]
}
With one aggregate I can come up with a time difference and isolate the predictions:
pipeline1 = [
{ "$unwind" : "$predictions" },
{ "$project" :
{
"timeDiff" : { "$subtract": ["$predictions.time", "$t_id"]},
"madeFor" : "$predictions.time",
"_id":0,
"estimate": "$predictions.prediction"
}}]
list(col.aggregate(pipeline3))
Resulting in a dataset like:
[{u'estimate': 77.60785714285714,
u'madeFor': datetime.datetime(2015, 10, 28, 0, 0),
u'timeDiff': 3600000L}, ... ]
But I still need to match these with the corresponding "time_collected" to calculate the errors, i.e.
`$subtract[prediction,value_at_time_collected]`
How can I do this?

MongoDB $elemMatch of $elemMatch and good practice

H,
I'm trying to update the version field in this object but I'm not able to make a query with 2 nested $match. So what I would like to do is get the record with file id 12 and version 1.
I would ask also if is it a good practice have more the one nested array in mongoDB (like this object)...
Query:
db.collection.find({"my_uuid":"434343"},{"item":{$elemMatch:{"file_id":12,"changes":{$elemMatch:{"version":1}}}}}).pretty()
Object:
{
"my_uuid": "434343",
"item": [
{
"file_id": 12,
"no_of_versions" : 1,
"changes": [
{
"version": 1,
"commentIds": [
4,
5,
7
]
},
{
"version": 2,
"commentIds": [
10,
11,
15
]
}
]
},
{
"file_id": 234,
"unseen_comments": 3,
"no_of_versions" : 2,
"changes": [
{
"version": 1,
"commentIds": [
100,
110,
150
]
}
]
}
]
}
Thank you
If you want the entire documents that satisfy the criteria returned in the result, then I think it's fine. But if you want to limit the array contents of item and changes to just the matching elements, then it could be a problem. That's because, you'll have to use the $ positional operator in the projection to limit the contents of the array and only one such operator can appear in the projection. So, you'll not be able to limit the contents of multiple arrays within the document.

MongoDB: Embedded docs that do NOT match query

I am working on a Mongo database, where I need users to be able to specify dates when they won't be available. I started with this structure:
{
"_id": "demo-spe",
"SC": [ { "SS": 14, "SA": [ 2, 3, 5 ] } ],
"SU": [
{ "IY": 2013, "IM": 12, "ID": 30, "H0": 0, "N0": 0, "H1": 23, "N1": 59 },
{ "IY": 2013, "IM": 12, "ID": 31, "H0": 0, "N0": 0, "H1": 23, "N1": 59 }
]
}
Using this structure, if I want to know which users will be available on a certain date, that is, the "SU" array should NOT have a document that matches IY:(year), IM:(month) and ID:(day). I am really lost with $and and $nin, could please someone guide me?
Thanks, and sorry for the noob question and the non-descriptive fields! :)
You can use a combination of $elemMatch and $not to do this. $elemMatch to match against multiple fields in the same array element, and $not to perform a logical NOT on the expression:
db.test.find({SU: {$not: {$elemMatch: {IY:2013, IM:12, ID:29}}}})

Is there a way to upsert a list with a single query?

I know this question has been asked before, but that's a different scenario.
I'd like to have a collection like this:
{
"_id" : ObjectId("4c28f62cbf8544c60506f11d"),
"pk": 1,
"forums": [{
"pk": 1,
"thread_count": 10,
"post_count": 20,
}, {
"pk": 2,
"thread_count": 5,
"post_count": 24,
}]
}
What I want to do is to upsert a "forum" item, incrementing counters or adding an item if it does not exist.
For example to do something like this (I hope it makes sense):
db.mycollection.update({
"pk": 3,
"forums.pk": 2
}, {
"$inc": {"forums.$.thread_count": 1},
"$inc": {"forums.$.post_count": 1},
}, true)
and have:
{
"_id" : ObjectId("4c28f62cbf8544c60506f11d"),
"pk": 1,
"forums": [{
"pk": 1,
"thread_count": 10,
"post_count": 20,
}, {
"pk": 2,
"thread_count": 5,
"post_count": 24,
}]
},
{
"_id" : ObjectId("4c28f62cbf8544c60506f11e"),
"pk": 3,
"forums": [{
"pk": 2,
"thread_count": 1,
"post_count": 1,
}]
}
I can surely make it in three steps:
Upsert the whole collection with a new item
addToSet the forum item to the list
increment forum item counters with positional operator
That's to say:
db.mycollection.update({pk:3}, {pk:3}, true)
db.mycollection.update({pk:3}, {$addToSet: {forums: {pk:2}}})
db.mycollection.update({pk:3, 'forums.pk': 2}, {$inc: {'forums.$.thread_counter': 1, {'forums.$.post_counter': 1}})
Are you aware of a more efficient way to do it?
TIA, Germano
As you may have discovered, the positional operator cannot be used in upserts:
The positional operator cannot be combined with an upsert since it requires a matching array element. If your update results in an insert then the "$" will literally be used as the field name.
So you won't be able to achieve the desired result in a single query.
You have to separate the creation of the document from the counter update. Your own solution is on the right track. It can be condensed into the following two queries:
// optionally create the document, including the array
db.mycollection.update({pk:3}, {$addToSet: {forums: {pk:2}}}, true)
// update the counters in the array item
db.mycollection.update({pk:3, 'forums.pk': 2}, {$inc: {'forums.$.thread_counter': 1, 'forums.$.post_counter': 1}})