NoSQL aggregate command - mongodb

I am new to NoSQL and trying to figure out how the aggregate works. It keeps erroring everytime I run my command.
db.restaurants.aggregate([
{ $match: { loaction: "London"}},
{ $group: { _id: "$type_of_food"}}
]);
What are I doing wrong? This is using the Mongodb.
Identify the types of restaurant available in London, as well as their count; use the
aggregate( ) function

You need accumulator option to the group stage , example:
db.restaurants.aggregate([
{
$match: {
location: "London"
}
},
{
$group: {
_id: "$type_of_food",
count: {
$sum: 1
}
}
}
])
playground

Related

MongoDB get only the last documents per grouping based on field

I have a collection "TokenBalance" like this holding documents of this structure
{
_id:"SvVV1qdUcxNwSnSgxw6EG125"
balance:Array
address:"0x6262998ced04146fa42253a5c0af90ca02dfd2a3"
timestamp:1648156174658
_created_at:2022-03-24T21:09:34.737+00:00
_updated_at:2022-03-24T21:09:34.737+00:00
}
Each address has multiple documents like of structure above based on timestamps.
So address X can have 1000 objects with different timestamps.
What I want is to only get the last created documents per address but also pass all the document fields into the next stage which is where I am stuck. I don't even know if the way I am grouping is correctly done with the $last operator. I would appreciate some guidance on how to achieve this task.
What I have is this
$group stage (1st stage)
{
_id: '$address',
timestamp: {$last: '$timestamp'}
}
This gives me a result of
_id:"0x6262998ced04146fa42253a5c0af90ca02dfd2a3"
timestamp:1648193827320
But I want the other fields of each document as well so I can further process them.
Questions
1) Is it the correct way to get the last created document per "address" field?
2) How can I get the other fields into the result of that group stage?
Use $denseRank
db.collection.aggregate([
{
$setWindowFields: {
partitionBy: "$address",
sortBy: { timestamp: -1 },
output: { rank: { $denseRank: {} } }
}
},
{
$match: { rank: 1 }
}
])
mongoplayground
I guess you mean this:
{ $group: {
_id: '$address',
timestamp: {$last: '$timestamp'},
data: { $push: "$$ROOT" }
} }
If the latest timestamp is also the last sorted by _id you can use something like this:
[{$group: {
_id: '$_id',
latest: {
$last: '$$ROOT'
}
}}, {$replaceRoot: {
newRoot: '$latest'
}}]

Is there a way to use find and aggregate together in MongoDB?

I m a MongoDB begginer and I have the following problem:
I have a document format(sorry for lack of definition) as follows in MongoDB:
And I want to query the top 10 albums of the worst genre of a decade I choose.
Firstly I did an aggregate that gave me in the last stage the worst genre of the decade I choose to use as comparison later (BDA1 being my database and album my collection I want to aggregate and find on):
BDA1.album.aggregation(
[
{
$addFields: {
release_date: {
$toDate: "$release_date"
}
}
},
{
$addFields: {
sales_amount: {
$convert: {
input: "$sales_amount",
to: "int"
}
}
}
},
{
$match: {
"release_date": {
$gte: new ISODate("2009-01-01"),
$lt: new ISODate("2021-01-01")
}
}
},
{
$unwind: {
path: "$band.band_genre",
}
},
{
$group: {
_id: "$band.band_genre",
total: {
$sum: "$sales_amount"
}
}
},
{
$sort: {
total: 1
}
},
{
$limit: 1
}
])
(Sorry for the lack of good formatting but I took the code from a pipeline I used to do the aggregation in MongoDB Compass.)
That resulted in:
But my question now is: how do I do to use that aggregate result in what I can only assume is a find command where band.band_genre equals to the genre I just calculated in the aggregation?
I have been searching SO for a while with no results and google as well.
Any suggestions?
(Anything that I have forgot to mention that u feel is important to understand the problem please say and I will edit it in)

Count nested wildcard array mongodb query

I have the following data of users and model cars:
[
{
"user_id":"ebebc012-082c-4e7f-889c-755d2679bdab",
"car_1a58db0b-5449-4d2b-a773-ee055a1ab24d":1,
"car_37c04124-cb12-436c-902b-6120f4c51782":0,
"car_b78ddcd0-1136-4f45-8599-3ce8d937911f":1
},
{
"user_id":"f3eb2a61-5416-46ba-bab4-459fbdcc7e29",
"car_1a58db0b-5449-4d2b-a773-ee055a1ab24d":1,
"car_0d15eae9-9585-4f49-a416-46ff56cd3685":1
}
]
I want to see how many users have a car_ with the value 1 using mongodb, something like:
{"car_1a58db0b-5449-4d2b-a773-ee055a1ab24d": 2}
For this example.
The issue is that I will never know how are the fields car_ are going to be, they will have a random structure (wildcard).
Notes:
car_id and user_id are at the same level.
The car_id is not given, I simply want to know for the entire database which are the most commmon cars_ with value 1.
$group by _id and convert root object to array using $objectToArray,
$unwind deconstruct root array
$match filter root.v is 1
$group by root.k and get total count
db.collection.aggregate([
{
$group: {
_id: "$_id",
root: { $first: { $objectToArray: "$$ROOT" } }
}
},
{ $unwind: "$root" },
{ $match: { "root.v": 1 } },
{
$group: {
_id: "$root.k",
count: { $sum: 1 }
}
}
])
Playground

Reusing/splitting $match results in a mongo aggregation

I have a mongo collection that stores data on page views such as location, user type (e.g. admin, user) and time spent on page. I want to use $match to get a subset of the documents and then use $group to group them by state and also by user type. The $match is rather expensive, so I was wondering if there was a way through the aggregation pipeline to somehow reuse the $match and get two sets of grouped data rather than needing to run two aggregates.
Current js pseudocode:
groupedByState = Views.aggregate([
$match: { ... },
$group: {
_id: '$state',
secondsViewed: { $avg: '$seconds_viewed' },
},
])
groupedByUserType = Views.aggregate([
$match: { ... },
$group: {
_id: '$user_type',
secondsViewed: { $avg: '$seconds_viewed' },
},
])
You can use the $facet aggregation operator to perform multiple $group operations against the output of the $match:
Views.aggregate([
$match: { ... },
$facet: {
byState: [{
$group: {
_id: '$state',
secondsViewed: { $avg: '$seconds_viewed' }
}
}],
byUserType: [
$group: {
_id: '$user_type',
secondsViewed: { $avg: '$seconds_viewed' }
}
}]
}
])

Mongoose cant seem to aggregate a sum and return all the items

I have this mongoose query that im running
db.accounts.aggregate([{
$unwind: "$Publishers"
}, {
$group: {
_id: "$Profile._id",
reachTotal: {
$sum: "$Publishers.reach"
},
Publishers: {
$push: "$Publishers"
},
Profile: {
$first: "$Profile"
}
}
}, {
$sort: {
reachTotal: 1
}
}])
It works fine, but the problem is that some of the records dont have '$Publishers.reach'. Mongoose doesn't return those records with the sum of null, undefined or 0. Is there a way to have mongoose return them?
You'll have to tell mongodb what to do in the form of a cond statement or the ifNull statement depending on your document structure.
http://docs.mongodb.org/manual/reference/operator/aggregation/cond/
http://docs.mongodb.org/manual/reference/operator/aggregation/ifNull/
...
reachTotal: { $sum: { $ifNull: ["$Publishers.reach", 0] } }