I have more than thousand of documents in my mongoDB collection where each document represents the data for a song like this:
{
"_id": ObjectID("612e03a790c3d3189845589b"),
"artist": "3 Doors Down",
"title": "Landning in London",
"album": "Another 700 Miles",
"genre": "Seventeen Days",
"trackNumber": 5,
"year": 2005,
"rating": 3,
"duration": "4:32",
"country": "United States",
}
Now with the help of the aggregation pipeline I want to group my collections the following way. So Far I could do grouping for 1 stage but I struggle to push through the complete root document until end and do this nested grouping.
List all genres --> list all artists within this genre --> list all albums of this artist within this genre --> list the COMPLETE root document for all songs of this album:
{
[
{
"genreName": "Alternative Rock",
"artists": [
{
"artistName": "3 Doors Down",
"albums": [
{
"albumName": "Seventeen Days",
"songs": [
{
"_id": ObjectID(612e03a790c3d3189845589b),
"artist": "3 Doors Down",
"title": "Landning in London",
"album": "Another 700 Miles",
"genre": "Seventeen Days",
"trackNumber": 5,
"year": 2005,
"rating": 3,
"duration": "4:32",
"country": "United States",
}
]
}
]
}
]
}
]
}
This one should work:
db.collection.aggregate([
{
$group: {
_id: { genreName: "$genre", artistName: "$artist", albumName: "$album" },
songs: { $push: "$$ROOT" }
}
},
{
$group: {
_id: { genreName: "$_id.genreName", artistName: "$_id.artistName" },
albums: { $push: { albumName: "$_id.albumName", songs: "$songs" } }
}
},
{
$group: {
_id: "$_id.genreName",
artists: { $push: { artistsName: "$_id.artistsName", albums: "$albums" } }
}
},
{ $project: { _id: 0, genreName: "$_id", artists: 1 } }
])
Related
I have a mongo collection with following structure:
{
"orderID": 123456,
"orderDate": { "$date": { "$numberLong": "1660037740974" } },
"invoiceLines": {
"itemLines": {
"itemLine": [
{
"itemID": "id1",
"itemName": "Item1",
"unitCost": 500,
"qtySold": 1,
},
{
"itemID": "id2",
"itemName": "Item2",
"unitCost": 750,
"qtySold": 2,
}
]
}
},
},
{
"orderID": 654321,
"orderDate": { "$date": { "$numberLong": "1660037740974" } },
"invoiceLines": {
"itemLines": {
"itemLine": [
{
"itemID": "id1",
"itemName": "Item1",
"unitCost": 500,
"qtySold": 2,
},
{
"itemID": "id3",
"itemName": "Item3",
"unitCost": 600,
"qtySold": 1,
}
]
}
},
},
etc.
I'm trying to find the aggregate sales quantities for each item across all orders. For example, for the above records we've sold 3 x Item1, 2 x Item2, and 1 x Item3.
I've tried to create an aggregate query for this, but it only returns the total order count for each item and not the total quantities sold across the orders.
Is this accomplished by using the aggregated methods of mongoDB? Is anyone able to assist me in building a proper query to accomplish the above?
Many thanks
You can use $unwind and then $group to
split your orders in one document per order-item
then group them together using $sum to add the quantities up
aggregation pipeline:
db.collection.aggregate([
{
$unwind: "$invoiceLines.itemLines.itemLine"
},
{
$group: {
_id: "$invoiceLines.itemLines.itemLine.itemID",
amount: {
"$sum": "$invoiceLines.itemLines.itemLine.qtySold"
}
}
}
])
Example Output for your example data:
[
{
"_id": "id3",
"amount": 1
},
{
"_id": "id2",
"amount": 2
},
{
"_id": "id1",
"amount": 3
}
]
I'm very new with mongoose. Can mongoose do something like i want to see how many linkview of James where store is Red only . The expected outcome should be linkview = 2 because 1+1. Please help
So this is User schema
{
"_id": "234",
"name": "James",
"__v": 0,
}
So this is affiliatelink schema
{
"_id": "11",
"store": "Red",
"linkview": "1",
"date": 12/12/12,
"affiliate": "James"
},
{
"_id": "22",
"store": "Red",
"linkview": "1",
"date": 13/12/12,
"affiliate": "James"
},
{
"_id": "33",
"store": "Blue",
"linkview": "1",
"date": 13/12/12,
"affiliate": "James"
}
Here is an aggregation you're looking for:
db.collection.aggregate([
{
$match: {
"affiliate": "James",
store: "Red"
}
},
{
$group: {
_id: null,
"linkview_count": {
$sum: 1
}
}
},
{
$project: {
_id: 0
}
}
])
The result will be:
[
{
"linkview_count": 2
}
]
Playground: https://mongoplayground.net/p/lPPhv9_w4iT
What I'm trying to do is add up the sum of the scores for any German Restaurant in Manhattan. I want to return the top 5 restaurants with their name and total score.
Here is the setup of the json data I'm working with:
{
"address": {
"building": "1007",
"coord": [ -73.856077, 40.848447 ],
"street": "Morris Park Ave",
"zipcode": "10462"
},
"borough": "Bronx",
"cuisine": "Bakery",
"grades": [
{ "date": { "$date": 1393804800000 }, "grade": "A", "score": 2 },
{ "date": { "$date": 1378857600000 }, "grade": "A", "score": 6 },
{ "date": { "$date": 1358985600000 }, "grade": "A", "score": 10 },
{ "date": { "$date": 1322006400000 }, "grade": "A", "score": 9 },
{ "date": { "$date": 1299715200000 }, "grade": "B", "score": 14 }
],
"name": "Morris Park Bake Shop",
"restaurant_id": "30075445"
}
I've tried multiple variations of this:
db.restaurants.aggregate([{$unwind: "$grades"}, {$group: {_id: {borough: "Manhattan", cuisine:"German"}, total:{$sum:"scores"}}}])
And this is what keeps getting returned. I'm new to MongoDb and I'm just not sure what I'm doing wrong.
{ "_id" : { "borough" : "Manhattan", "cuisine" : "German" }, "total" : 0 }
So here is an aggregation that might work assuming the average score is what is measured...
Query:
db.restaurants.aggregate([
{ $match: { "borough": "Manhattan", "cuisine": "German" } },
{ $unwind: "$grades" },
{ $group: {
"_id": "$name",
"avg_score": { $avg: "$grades.score" }
}
},
{ $sort: { "avg_score": -1 } },
{ $limit: 5 }
]).pretty()
Pipeline Explaination:
match on borough and cuisine to filter to only desirable conditions
Unwind the grades array to flatten structure for review
group on the restaurant name and get the average score
Sort on the average score descending to get the top scores at the
top of the list
Limit output to the top 5 restaurants.
EDIT:
Sort by sum instead of average...
db.restaurants.aggregate([
{ $match: { "borough": "Manhattan", "cuisine": "German" } },
{ $unwind: "$grades" },
{ $group: {
"_id": "$name",
"avg_score": { $avg: "$grades.score" },
"sum_score": { $sum: "$grades.score" }
}
},
{ $sort: { "sum_score": -1 } },
{ $limit: 5 }
]).pretty()
I have three documents:
{
"id_user": "t57092501745ad6285ac58c22",
"name": "Day #1",
"date": {
"$date": "2016-04-21T20:50:00.190Z"
},
"text": "My text"
}
{
"id_user": "t57092501745ad6285ac58c22",
"name": "Day #2",
"date": {
"$date": "2016-04-22T20:50:00.190Z"
},
"text": "My text"
}
{
"id_user": "t57092501745ad6285ac58c22",
"name": "Day #3",
"date": {
"$date": "2016-04-22T20:51:00.190Z"
},
"text": "My text"
}
and I need to group these for day, so I do:
{
"$match": {
"id_user": "t57092501745ad6285ac58c22"
}
}, {
"$sort": {
"date": -1
}
}, {
"$group": {
"_id": {
$dayOfYear: "$date"
},
"data": {
"$push": {
"id_user": "$id_user",
"name": "$name",
"date": "$date",
"text": "$text"
},
},
}
}
and the result is:
{
{
_id: 113,
data: [{
"id_user": "t57092501745ad6285ac58c22",
name: "Day #1",
date: "2016-04-22T20:51:00.190Z",
text: "My text"
}]
}, {
_id: 114,
data: [{
"id_user": "t57092501745ad6285ac58c22",
name: "Day #3",
date: "2016-04-23T20:51:00.190Z",
text: "My text"
}, {
"id_user": "t57092501745ad6285ac58c22",
name: "Day #2",
date: "2016-04-23T20:50:00.190Z",
text: "My text"
}]
}
}
and it's ok, but the order is not what I need:
{ Day #1 }, { Day #3, Day #2 }
if I change the sort to { "date": 1 } I can invert the order of the 2 groups, this way:
{ Day #3, Day #2 }, { Day #1 }
but I don't know how tho change also the order inside the sub-array, to obtain the correct:
{ Day #1 }, { Day #2, Day #3 }
What's the correct way?
If you want the items in the "array" to be in "ascending" order, then your $sort order is wrong, and you need to reverse it. Also output from $group as a "document" is not ordered in any way. So if you want a specific order then you need to actually $sort on the returned _id as well:
[
{ "$match": {
"id_user": "t57092501745ad6285ac58c22"
}},
{ "$sort": { "date": 1 } }
{ "$group": {
"_id": { "$dayOfYear": "$date" },
"data": {
"$push": {
"id_user": "$id_user",
"name": "$name",
"date": "$date",
"text": "$text"
}
}
}},
{ "$sort": { "_id": 1 } }
]
Then both orders are then correct
I have a collection with objects like this:
{
"_id": ObjectId("52ed12c144aecc4bf004d0b6"),
"title": "myBook",
"summary": "This is a book summary",
"chapters": [
{
"number": 1
"created_at": ISODate("2013-12-17T23:00:00Z")
},
{
"number": 2
"created_at": ISODate("2014-12-17T23:00:00Z")
}
]
"covers": [
"http://url.com/cover1.jpg",
"http://url.com/cover2.jpg",
],
"urls": [
"http://url.com/myBook",
"http://url.com/myBook/option2"
],
"genres": [
"comedy",
"romantic"
],
"created_at": ISODate("2012-12-17T23:00:00Z"),
"modify_at": ISODate("2014-02-01T15:41:48.149Z")
}
I only want to get books which 'crated_at' >= '2012-12-17T23:00:00Z' with only the chapters which 'created_at' > "2013-12-17T23:00:00Z". (As a filter)
My output json should be something like this:
{
"_id": ObjectId("52ed12c144aecc4bf004d0b6"),
"title": "myBook",
"summary": "This is a book summary",
"chapters": [
{
"number": 2
"created_at": ISODate("2014-12-17T23:00:00Z")
}
]
"covers": [
"http://url.com/cover1.jpg",
"http://url.com/cover2.jpg",
],
"urls": [
"http://url.com/myBook",
"http://url.com/myBook/option2"
],
"genres": [
"comedy",
"romantic"
],
"created_at": ISODate("2012-12-17T23:00:00Z"),
"modify_at": ISODate("2014-02-01T15:41:48.149Z")
}
In the query output could be books without any chapters, others with a subset of all their chapters or books with all their chapters.
For to search books by 'created_at' I query by:
db.books.find({ created_at: {$gte: ISODate("2012-12-17T23:00:00Z")} })
but I don't know what I have to add for to filter the chapters in the output of this result.
You could try to do it with aggregation framework.
db.chapters.aggregate(
{ $match: { created_at: {$gte: ISODate("2012-12-17T23:00:00Z")} } },
{ $unwind: "$chapters" },
{ $match: { "chapters.created_at": {$gte: ISODate("2013-12-17T23:00:00Z")} } },
{ $group:
{
_id:
{
id: "$_id",
title: "$title",
summary: "$summary",
covers: "$covers",
urls: "$urls",
genres: "$genres",
created_at: "$created_at",
modify_at: "$modify_at"
},
chapters: { $push: "$chapters" }
}
},
{ $project:
{
_id: "$_id.id",
title: "$_id.title",
summary: "$_id.summary",
chapters: "$chapters",
covers: "$_id.covers",
urls: "$_id.urls",
genres: "$_id.genres",
created_at: "$_id.created_at",
modify_at: "$_id.modify_at"
}
}
)