MongoDB aggregate $avg always returns zero - mongodb

I'm trying to get an average over a set of records from MongoDB, but it is always returning zero.
db.entries.aggregate([
{ $match : { "date" : { $gte : 1465672815466 }, "type" : "sgv" } },
{ $group : { _id : null, avgBG : { $avg: "sgv" } } }
])
I'm very new to MongoDB and I'm not sure if somehow this is caused by records coming back where there is no "sgv" value or if I'm doing something else wrong here.

Related

Count of a nested value of all entries in mongodb collection

I have a collection named outbox which has this kind of structure
"_id" :ObjectId("5a94e02bb0445b1cc742d795"),
"track" : {
"added" : {
"date" : ISODate("2020-12-03T08:48:51.000Z")
}
},
"provider_status" : {
"job_number" : "",
"count" : {
"total" : 1,
"sent" : 0,
"delivered" : 0,
"failed" : 0
},
"delivery" : []
}
I have 2 tasks. First I want the sum of all the "total","sent","failed" on all the entries in the collection no matter what their objectId is. ie I want sum of all the "total","sent","delivered" and "failed". Second I want all these only for a given object Id between Start and End date.
I am trying to find total using this query
db.outbox.aggregate(
{ $group: { _id : null, sum : { $sum: "$provider_status.count.total" } } });
But I am getting this error as shown
Since I do not have much experience in mongodb I don't have any idea how to do these two tasks. Need help here.
You are executing this in Robo3t seems like.
You need to enclose this in an array like
db.test.aggregate([ //See here
{
$group: {
_id: null,
sum: {
$sum: "$provider_status.count.total"
}
}
}
])//See here
But it's not the case with playground as they handle them before submitting to the server

mongoDB distict problems

It's one of my data as JSON format:
{
"_id" : ObjectId("5bfdb412a80939b6ed682090"),
"accounts" : [
{
"_id" : ObjectId("5bf106eee639bd0df4bd8e05"),
"accountType" : "DDA",
"productName" : "DDA1"
},
{
"_id" : ObjectId("5bf106eee639bd0df4bd8df8"),
"accountType" : "VSA",
"productName" : "VSA1"
},
{
"_id" : ObjectId("5bf106eee639bd0df4bd8df9"),
"accountType" : "VSA",
"productName" : "VSA2"
}
]
}
I want to make a query to get all productName(no duplicate) of accountType = VSA.
I write a mongo query:
db.Collection.distinct("accounts.productName", {"accounts.accountType": "VSA" })
I expect: ['VSA1', 'VSA2']
I get: ['DDA','VSA1', 'VSA2']
Anybody knows why the query doesn't work in distinct?
Second parameter of distinct method represents:
A query that specifies the documents from which to retrieve the distinct values.
But the thing is that you showed only one document with nested array of elements so whole document will be returned for your condition "accounts.accountType": "VSA".
To fix that you have to use Aggregation Framework and $unwind nested array before you apply the filtering and then you can use $group with $addToSet to get unique values. Try:
db.col.aggregate([
{
$unwind: "$accounts"
},
{
$match: {
"accounts.accountType": "VSA"
}
},
{
$group: {
_id: null,
uniqueProductNames: { $addToSet: "$accounts.productName" }
}
}
])
which prints:
{ "_id" : null, "uniqueProductNames" : [ "VSA2", "VSA1" ] }

Mongo DB - how to query for id dependent on oldest date in array of a field

Lets say I have a collection called phone_audit with document entries of the following form - _id which is the phone number, and value containing items that always contains 2 entries (id, and a date).
Please see below:
{
"_id" : {
"phone_number" : "+012345678"
},
"value" : {
"items" : [
{
"_id" : "c14b4ac1db691680a3fb65320fba7261",
"updated_at" : ISODate("2016-03-14T12:35:06.533Z")
},
{
"_id" : "986b58e55f8606270f8a43cd7f32392b",
"updated_at" : ISODate("2016-07-23T11:17:53.552Z")
}
]
}
},
......
I need to get a list of _id values for every entry in that collection representing the older of the two items in each document.
So in the above - result would be [c14b4ac1db691680a3fb65320fba7261,...]
Any pointers at the type of query to execute would be v.helpful even if the exact syntax is not correct.
With aggregate(), you can $unwind value.items, $sort by update_at, then use $first to get the oldest:
[
{
"$unwind": "$value.items"
},
{
"$sort": { "value.items.updated_at": 1 }
},
{
"$group":{
_id: "$_id.phone_number",
oldest:{$first:"$value.items"}
}
},
{
"$project":{
value_id: "$oldest._id"
}
}
]

Exclude 0 values from mongodb $avg but keeping other fields

I run some aggregation queries on MongoDB 3.2.
I would like to group documents by a field with an average on another numeric field.
I need the average to ignore the 0 values.
The problem is I can't entirely filter the document, cause there is another field I need for a count.
Let's illustrate :
This is the structure of my documents:
{"stringToGroupByOn":"foo", "valueToAvg":42, "valueToSum":21}
{"stringToGroupByOn":"foo", "valueToAvg":0, "valueToSum":13}
I can't just filter like this:
db.foobar.aggregate([
{
$match : { valueToAvg : { $gt : 0 } }
},
{
$group : {
_id : '$stringToGroupByOn',
avg : { $avg : '$valueToAvg' },
count : { $sum : '$valueToSum' }
}
}
])
Because I lose the value 13 for the count.
Do you think there is a way to do it in only one query ?
You can use $cond in projection to set null instead of 0, as null is not considered when using average.
db.avg.aggregate([
{$project:{
_id:1,
valueToSum:1,
stringToGroupByOn:1,
valueToAvg:{$cond:
{ if: { $eq: [ "$valueToAvg", 0 ] },
then: null,
else: "$valueToAvg" }}
}},
{
$group : {
_id : '$stringToGroupByOn',
avg : { $avg : '$valueToAvg' },
count : { $sum : '$valueToSum' }
}
}
output:
{
"_id" : "foo",
"avg" : 42.0,
"count" : 34.0
}

Nested mongo query

Here is what the data looks like:
{
"_id" : {
"item" : "1",
"state" : "something"
},
"things" : {
"ordered" : 2,
"cost" : 123
}
}
I try to query for all doc of item 1, there are many state for that item. I know i can get that record using db.orders.find({_id:{item:"1", state: "something"}}). But I would like to get all states I try something like db.orders.find({_id:{item:"1", state: {$exists: true}}})
But that doesn't seem to work. What am i doing wrong?
If you want to get the list of all the different states you could use.
db.orders.distinct("_id.state");
If you want to get the list of all the states in your collection
db.orders.find({}, {"_id.state": 1});
I really want to get the things.cost for all the states for a given
item
db.orders.aggregate([
{ $group : {
_id : { item : "$_id.item" , state : "$_id.state"},
cost: { $push : "$things.cost" }
}
}
]);
If you want the sum instead of the elements of the group by use $sum instead of $push
How do i get for certain item?
db.orders.aggregate([
{ $match : { "_id.item" : "YOUR_ID" }},
{ $group : {
_id : { item : "$_id.item" , state : "$_id.state"},
cost: { $push : "$things.cost" }
}
}
]);