Is there a way to use find and aggregate together in MongoDB? - 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)

Related

MongoDB Aggregation - get docs where property value is of certain value inside another collection

I am new to mongo and therefore having a hard time achieving what I want to do. I try to explain as best as I can so hopefully you will understand my question.
I have an aggregation like this running a collection named TokenBalance where the documents inside have this structure
{"address": string, "balance": [array of balance objects]}
[
{
$sort: {
updatedAt: -1
}
},
{
$group: {
_id: "$address",
balance: {
$last: "$balance"
}
}
},
{
$unwind: {
path: "$balance"
}
},
{
$group: {
_id: "$balance.symbol",
count: {
$sum: {
$toDecimal: "$balance.balance"
}
}
}
},
{
$project: {
_id: 0,
symbol: "$_id",
total: "$count"
}
}
];
which is almost what I am trying to do. The output of this looks like this
{
symbol:"Playboy"
total:10193456759513379777140001203028
}
What I usually wanted tho, is to only get the TokenBalance documents where the TokenBalance.address is inside another collection _AddressSyncStatus where AddressSyncStatus.value is greater than numberX
This is how a document of _AddressSyncStatus looks like
{
"address": "some string address", "value": someNumber
}
So basically, get all TokenBalance where TokenBalance.address is inside _AddressSyncStatus and its value is greater than whatever I specify.
From there on I would then add the stages I already managed to code.
What I don't know and don't seem to get to work, is how to add a $lookup (if that is what I need for that) and where to add that.
My last try was adding these as the first stages which I initially thought work.
{
'$lookup': {
'from': '_AddressSyncStatus',
'localField': 'address',
'foreignField': 'address',
'as': 'synced_address'
}
}, {
'$unwind': {
'path': '$synced_address'
}
}, {
'$match': {
'synced_address.value': {
'$lt': 1
}
}
}
The issue with this is, that AddressSyncStatus has documents with a value of for example 0.2 or 0.4555 etc.
when I put $lt: 1 it is not returning any documents. If I put int $gte:1 it shows a whole bunch of documents where AddressSyncStatus.value is bigger than 1.
Not sure why its not working with $lt or $lte when AddressSyncStatus has values less than that.

NoSQL aggregate command

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

MongoDB aggregation: How to get the index of a document in a collection depending sorted by a document property

Assume I have a collection with millions of documents. Below is a sample of how the documents look like
[
{ _id:"1a1", points:[2,3,5,6] },
{ _id:"1a2", points:[2,6] },
{ _id:"1a3", points:[3,5,6] },
{ _id:"1b1", points:[1,5,6] },
{ _id:"1c1", points:[5,6] },
// ... more documents
]
I want to query a document by _id and return a document that looks like below:
{
_id:"1a1",
totalPoints: 16,
rank: 29
}
I know I can query the whole document, sort by descending order then get the index of the document I want by _id and add one to get its rank. But I have worries about this method.
If the documents are in millions won't this be 'overdoing' it. Querying a whole collection just to get one document? Is there a way to achieve what I want to achieve without querying the whole collection? Or the whole collection has to be involved because of the ranking?
I cannot save them ranked because the points keep on changing. The actual code is more complex but the take away is that I cannot save them ranked.
Total points is the sum of the points in the points array. The rank is calculated by sorting all documents in descending order. The first document becomes rank 1 and so on.
an aggregation pipeline like the following can get the result you want. but how it operates on a collection of millions of documents remains to be seen.
db.collection.aggregate(
[
{
$group: {
_id: null,
docs: {
$push: { _id: '$_id', totalPoints: { $sum: '$points' } }
}
}
},
{
$unwind: '$docs'
},
{
$replaceWith: '$docs'
},
{
$sort: { totalPoints: -1 }
},
{
$group: {
_id: null,
docs: { $push: '$$ROOT' }
}
},
{
$set: {
docs: {
$map: {
input: {
$filter: {
input: '$docs',
as: 'x',
cond: { $eq: ['$$x._id', '1a3'] }
}
},
as: 'xx',
in: {
_id: '$$xx._id',
totalPoints: '$$xx.totalPoints',
rank: {
$add: [{ $indexOfArray: ['$docs._id', '1a3'] }, 1]
}
}
}
}
}
},
{
$unwind: '$docs'
},
{
$replaceWith: '$docs'
}
])

Is it possible to create multiple collections out of a fork (e.g. bucket or facet)

I was wondering if it's possible to create multiple collections (3 to be precise) when using facet and/or bucket. The documentation specifies that facet can't be used with out. So is there an alternative? I'm trying to do something like the following:
Split document in 3 categories (bucket / facet ???)
With these categories get an avg of some value
Output the query to 3 different collections, each collection have the name of the category
I have the following atm, which groups and filters everything, but if I'm using $out, it can only export to one document (so I got rid of $out)
db.getCollection('metingen').aggregate(
[
{
$unwind: "$parameters"
},
{
$group: {
_id : {
uur: { $hour: "$tijdstip" },
locatie: {
$map: {
input: "$loc.coordinates",
in: {
$divide: [
{ $trunc: { $multiply: [ '$$this', 1000 ] }},
1000
]
}
}
}
},
gemiddelde: {
$avg: "$parameters.value"
}
}
},
{
$sort: { "_id.uur" : 1 }
}
]
);
The filter value should be something like $parameters.soort, but I haven't added it here, but I experimented with it before. I'm looking for a way to do this in one query only if possible.
Thanks in advance!

Best usage for MongoDB Aggregate request

I would like to highlight a list of _id documents (with a limit) ranked in descending order (via their timestamp) based on a list of ObjectId.
Corresponding to this:
db.collection.aggregate( [ { $match: { _id: { $in: [ObjectId("X"), ObjectId("Y") ] } } }, { $sort: { timestamp: -1 } }, { $group: { _id: "$_id" } }, { $skip: 0 }, { $limit: 100 } ] )
Knowing that the list from the loop may contain way more than 1000 ObjectId (in $in array), do you think my solution is viable? Is not there a faster and less resource intensive way?
Best Regards.