$sortArray Issue (MongoDB) - mongodb

I have a section of my aggregate query that I cannot get to work for the life of me. I am running 6.0. The section of the query with the issue looks like this:
$project: {
_id: 0,
games: {
$sortArray: {
input: '$games',
sortBy: { date: -1 }
}
},
total: { $size: '$games' }
}
For some reason the $sortArray function is not working for me in that I am getting no output from the query at all. The query, however, will work if I remove this sort like this:
$project: {
_id: 0,
games: 1,
total: { $size: '$games' }
}
After studying the $sortArray documentation, I believe that I am implementing this into the pipeline correctly. Can anyone identify what the issue is? Here is the full pipeline for context:
const pipeline = [
{
$match: { _id: ObjectID( user_id ) }
},
{
$lookup: {
from: 'game',
localField: '_id',
foreignField: 'player_id',
pipeline: pipelineFilters,
as: 'owned_games'
}
},
{
$lookup: {
from: 'viewers',
pipeline: [
{ $match: { email: user_email } },
{
$lookup: {
from: 'games',
localField: 'game_id',
foreignField: '_id',
pipeline: pipelineFilters,
as: 'games'
}
},
{
$project: {
game: { $arrayElemAt: [ '$games', 0 ] }
}
},
{
$replaceRoot: {
newRoot: '$game'
}
}
],
as: 'viewing_games'
}
},
{
$project: {
games: {
$concatArrays: [ '$viewing_games', '$owned_games' ]
}
}
},
{
$project: {
_id: 0,
games: {
$sortArray: {
input: '$games',
sortBy: { date: -1 }
}
},
total: { $size: '$games' }
}
}
];
and example of the document structure right before the final $project:
{
_id: new ObjectId("6359ac2149c98388770fb2b3"),
games: [
{
_id: new ObjectId("63595544435af1b923d1bda1"),
name: 'game 1',
owner_id: new ObjectId("63595544435af1b923d1bd98"),
date: 2022-10-26T15:41:56.584Z,
status: 'draft',
createdAt: 2022-10-26T15:41:56.599Z,
updatedAt: 2022-10-26T15:41:56.599Z,
__v: 0
},
{
_id: new ObjectId("63595544435af1b923d1bd99"),
name: 'game 2',
owner_id: new ObjectId("63595544435af1b923d1bd8b"),
date: 2011-10-05T14:48:00.000Z,
status: 'draft',
createdAt: 2022-10-26T15:41:56.585Z,
updatedAt: 2022-10-26T15:41:56.585Z,
__v: 0
},
{
_id: new ObjectId("63595544435af1b923d1bd9b"),
name: 'game 3',
owner_id: new ObjectId("63595544435af1b923d1bd8b"),
date: 1990-01-01T01:22:00.000Z,
status: 'draft',
createdAt: 2022-10-26T15:41:56.588Z,
updatedAt: 2022-10-26T15:41:56.588Z,
__v: 0
},
{
_id: new ObjectId("63595544435af1b923d1bd9d"),
name: 'game 4',
owner_id: new ObjectId("63595544435af1b923d1bd8b"),
date: 2500-10-05T14:48:00.000Z,
status: 'draft',
createdAt: 2022-10-26T15:41:56.592Z,
updatedAt: 2022-10-26T15:41:56.592Z,
__v: 0
},
{
_id: new ObjectId("63595544435af1b923d1bd9f"),
name: 'game 5',
owner_id: new ObjectId("63595544435af1b923d1bd8b"),
date: 1995-12-25T01:22:00.000Z,
status: 'draft',
createdAt: 2022-10-26T15:41:56.595Z,
updatedAt: 2022-10-26T15:41:56.595Z,
__v: 0
}
]
}

We were using mongo:latest tag when launching our docker container which doesn't actually pull the latest mongo image...
Conclusion: assumptions are bad

Related

MongoDB Aggregation: Filter array with _id as string by ObjectId

I have the following collections:
const movieSchema = new Schema({
title: String
...
})
const userSchema = new Schema({
firstName: String,
lastName: String,
movies: [
movie: {
type: Schema.Types.ObjectId,
ref: 'Movie'
},
status: String,
feeling: String
]
...
})
I am trying to match up the movie (with all its details) with the user status and feeling for that movie, with the aggregation:
Movie.aggregate([
{ $match: { _id: ObjectId(movieId) } },
{
$lookup: {
from: 'users',
as: 'user_status',
pipeline: [
{ $match: { _id: ObjectId(userId) } },
{
$project: {
_id: 0,
movies: 1
}
},
{ $unwind: '$movies' }
]
}
},
])
Which returns:
[
{
_id: 610b678702500b0646925542,
title: 'The Shawshank Redemption',
user_status: [
{
"movies": {
"_id": "610b678702500b0646925542",
"status": "watched",
"feeling": "love"
}
},
{
"movies": {
"_id": "610b678502500b0646923627",
"status": "watched",
"feeling": "like"
}
},
{
"movies": {
"_id": "610b678502500b0646923637",
"status": "watched",
"feeling": "like"
}
},
]
}
]
My desired result is to match the first movie in user_status to get the eventual final result:
[
{
_id: 610b678702500b0646925542,
title: 'The Shawshank Redemption',
status: "watched",
feeling: "love"
}
]
I thought the next step in my pipeline would be:
{
$addFields: {
user_status: {
$filter: {
input: '$user_status',
cond: {
$eq: ['$$this.movies._id', '$_id']
}
}
}
}
}
But it doesn't work - Not sure if this $addFields is correct, and one problem I know is that my first _id is an ObjectId and the second appears to be a string.
If I understand correctly, you can $filter the user in the already existing $lookup pipeline, which will make things more simple later:
db.movies.aggregate([
{$match: {_id: ObjectId(movieId)}},
{
$lookup: {
from: "users",
as: "user_status",
pipeline: [
{$match: {_id: ObjectId(userId)}},
{$project: {
movies: {
$first: {
$filter: {
input: "$movies",
cond: {$eq: ["$$this.movie", ObjectId(movieId)]}
}
}
}
}
}
]
}
},
{
$project: {
title: 1,
feeling: {$first: "$user_status.movies.feeling"},
status: {$first: "$user_status.movies.status"}
}
}
])
See how it works on the playground example

3 level nested lookup with arrays

I am building an apllication with mongoose and node.js that enables you to post, comment, and like both the posts and the comments.
I am tryign to build a query that gets all the information from the db.
saw that answer nested 3 level lookup like in here MongoDB nested lookup with 3 levels.
it works, but the project filter returns me an error and if I remove it, I get some comments that looks like that:
"comments":
{
"user": [],
"likes": []
}
the argigate
postArgigate = [
{
//lookup for the post likes
$lookup: {
from: 'likes',
localField: '_id',
foreignField: 'postCommentID',
as: '_likes'
},
},
//the user wrote the post
{
$lookup: {
from: 'users',
localField: 'userID',
foreignField: '_id',
as: 'user'
},
},
{
$lookup: {
from: 'comments',
localField : 'commentsID',
foreignField : '_id',
as: 'comments'
},
},
//unwind the comments to do a nesting lookup
{
$unwind: {
path: "$comments",
preserveNullAndEmptyArrays: true
}
},
//lookup in the comments likes
{
$lookup: {
from: 'likes',
localField : 'comments._id',
foreignField : 'postCommentID',
as: 'comments._likes'
},
},
//lookup in the user that wrote the comment
{
$lookup: {
from: 'users',
localField: 'comments.userID',
foreignField: '_id',
as: 'comments.user'
},
},
{
$set: {
'comments.likes':'$comments._likes.userID',
'likes': '$_likes.userID'
}
},
{
$project: {
/////////FILTER NOT WORKING////////////
// 'comments': {
// $filter: { input: "$comments", as: "cm", cond: { $ifNull: ["$$cm._id", false] } }
// } , //returns an error
'comments.userID':0,
'comments.user.password':0,
'comments._likes':0,
'userID':0,
'user.password':0,
'commentsID':0,
'_likes': 0,
}
},
{
$group: {
_id : "$_id",
user:{$first:'$user'},
likes:{$first:'$likes'},
date:{$first:'$date'},
content:{$first:'$content'},
comments: { $push: "$comments" },
}
}
]
thank you for you help!
comments
[
{
_id: ObjectId("com1"),
userID:ObjectId("eliran1"),
content: 'comment 1',
date: 2022-03-02T22:55:16.224Z,
},
{
_id:ObjectId("com2"),
userID: ObjectId("eliran1"),
content: 'comment 2',
date: 2022-03-05T18:34:52.890Z,
__v: 0
}
]
posts
[
{
_id: new ObjectId("post1"),
userID: new ObjectId("eliran1"),
content: 'post 1',
commentsID: [],
date: 2022-03-05T18:28:11.487Z,
},
{
_id: new ObjectId("post2"),
userID: new ObjectId("shira1"),
content: 'post 2',
commentsID: [ObjectId("com1"),
ObjectId("com2") ],
date: 2022-03-05T18:34:46.364Z,
}
]
users
[
{
_id: new ObjectId("eliran1"),
user: 'eliran222',
password: '123456789',
email: 'fdfd#fdfd.com33',
gender: true,
__v: 0
},
{
_id: new ObjectId("shira1"),
user: 'shira3432',
password: '123456789',
email: 'fdrf#gfge.com',
gender: false,
}
]
likes
[
{
_id: ObjectId("like1"),
userID: ObjectId("eliran1"),
postCommentID:ObjectId("post1"),
},
{
_id:ObjectId("like2"),
userID: ObjectId("shira1"),
postCommentID:ObjectId("com1"),
}
]
expected results:
[
{
_id: new ObjectId("post1"),
user: {
user: 'eliran222',
email: 'fdfd#fdfd.com33',
gender: true,
},
content: 'post 1',
comments: [],
date: 2022-03-05T18:28:11.487Z,
likes:[{/*eliran`s user*/}]
},
{
_id: new ObjectId("post2"),
userID: {
_id: new ObjectId("shira1"),
user: 'shira3432',
email: 'fdrf#gfge.com',
gender: false,
},
content: 'post 2',
comments: [{
_id: ObjectId("com1"),
user:{
_id:objectId(eliran1)
user: 'eliran222',
email: 'fdfd#fdfd.com33',
gender: true,
},
content: 'comment 1',
date: 2022-03-02T22:55:16.224Z,
likes:[{/*shira`s user*/}]
},
{
_id:ObjectId("com2"),
user: {
objectId(eliran1)
user: 'eliran222',
email: 'fdfd#fdfd.com33',
gender: true,
},
content: 'comment 2',
date: 2022-03-05T18:34:52.890Z,
likes:[]
}],
date: 2022-03-05T18:34:46.364Z,
}
]
}
]

Getting `[ [Object] ]` as nested array of object response on MongoDB Aggregation query

I'm trying to do an aggregation on two collections that has a linkage between them, and I need to access information in an array of objects in one of those collections.
Here are the schemas:
User Schema:
{
_id: ObjectId,
username: String,
password: String,
associatedEvents: [
{
event_id: ObjectId,
isCreator: boolean,
access_level: String,
}
]
}
Event Schema:
{
_id: ObjectId,
title: String,
associated_users: [
{
user_id: ObjectId
}
]
}
I'm attempting to get the users associated to an event for a specific user, and then get their access level information. Here's the aggregation I have:
const eventsJoined = await Event.aggregate([
{
$match: {
$expr: { $in: [id, "$associatedUserIds"] },
},
},
{
$lookup: {
from: "users",
localField: "associatedUserIds",
foreignField: "_id",
as: "user_info",
},
},
{ $unwind: "$user_info" },
{
$unwind: {
path: "$user_info.associatedEvents",
preserveNullAndEmptyArrays: true,
},
},
{
$group: {
_id: "$_id",
title: { $first: "$title" },
description: { $first: "$description" },
startDate: { $first: "$startdate" },
userInfo: { $first: "$user_info" },
usersAssociatedEvents: { $push: "$user_info.associatedEvents" },
},
},
{
$project: {
title: 1,
description: 1,
startDate: 1,
userInfo: 1,
usersAssociatedEvents: "$usersAssociatedEvents",
},
},
]);
And this is the result I'm getting:
[
{
_id: 609d5ad1ef4cdbeb32987739,
title: 'hello',
description: 'desc',
startDate: null,
usersAssociatedEvents: [ [Object] ]
}
]
As you can see, the query is already aggregating the correct data. But the last thing that's tripping me up is the fact that the aggregation is [ [Object] ] for usersAssociatedEvents instead of the actual contents of the object. Any idea on why that would be?

How do I query sub document when using $lookup?

Here's my problem: I am trying to query subdocument bulk by it's property name. I can't find any operator to do that.
I have tried using $match like this - $match: { 'bulk.name': 'xyz' } but it doesn't work.
const query = [
{
$match: { user },
},
{
$group: {
_id: { bulk: '$bulk', status: '$status' },
count: { $sum: 1 },
},
},
{
$group: {
_id: '$_id.bulk',
status: { $addToSet: { status: '$_id.status', count: '$count' } },
},
},
{
$lookup: {
from: 'bulks',
localField: '_id',
foreignField: '_id',
as: 'bulk',
},
},
{
$replaceRoot: { newRoot: { $mergeObjects: [{ $arrayElemAt: ['$bulk', 0] }, '$$ROOT'] } },
},
{ $project: { bulk: 0 } },
]
sample data
items:
[{
_id: 6040 d71f40f98b3e3cc518c9,
type: 'Gateway',
name: 'Lite Bulk Group Ultra FE Dupe__3/4/2021, 12:36:38 PM',
description: '',
message: '{{name}} {{Message-optional}} {{another-one}} {{another-two}}',
group: 6017 b457f5105418b8099ab6,
user: 5 fc871135fd04f562aed3527,
schedule: 6040 d71f40f98b3e3cc518c2,
createdAt: 2021 - 03 - 04 T12: 48: 31.661 Z,
updatedAt: 2021 - 03 - 04 T12: 48: 31.661 Z,
__v: 0,
status: [Array]
}]

MongoDB: Sorting records by the sum of other collection [duplicate]

This question already has answers here:
Mongo order by length of array
(4 answers)
Sort By length of array mongodb query
(1 answer)
Closed 3 years ago.
I have two collections users and tasks and I want to sort the users by the sum of tasks that they created in tasks collection.
Users collection.
users: [
{ _id: ObjectId('1...'), username: 'jack' },
{ _id: ObjectId('2...'), username: 'john' },
{ _id: ObjectId('3...'), username: 'james' }
]
Tasks collection.
tasks: [
{ _id: ObjectId('...'), userId: '1...', taskName: 'task 1' },
{ _id: ObjectId('...'), userId: '1...', taskName: 'task 2' },
{ _id: ObjectId('...'), userId: '1...', taskName: 'task 3' },
{ _id: ObjectId('...'), userId: '2...', taskName: 'task 1' },
{ _id: ObjectId('...'), userId: '3...', taskName: 'task 1' },
{ _id: ObjectId('...'), userId: '3...', taskName: 'task 2' }
]
This is where I came so far.
UsersModel.aggregate([
{
$lookup: {
from: 'tasks',
localField: '_id',
foreignField: 'userId',
as: 'tasks'
}
},
{
$group: {
_id: '$_id',
totalTasks: { $sum: '$tasks.userId' }
}
},
{
$sort: { totalTasks: -1 }
}
], (err, res) => {
if (err) console.log(err)
console.log(res)
})
But I'm getting results like this.
[
{ _id: 1..., totalTasks: 0 },
{ _id: 2..., totalTasks: 0 },
{ _id: 3..., totalTasks: 0 }
]
But this is what I'm looking for.
[
{ _id: 1..., totalTasks: 3 },
{ _id: 3..., totalTasks: 2 },
{ _id: 2..., totalTasks: 1 }
]
I'm not sure this is the problem but the type of users._id is ObjectId and the type of tasks.userId is String. I'm stuck and need some help.
Easiest way:
{
$addFields: {
temp_id: {$toString: "$_id"}
}
},
{
$lookup: {
from: 'tasks',
localField: 'temp_id',
foreignField: 'userId',
as: 'tasks'
}
},
{
$addFields: {
totalTasks: {$size: "$tasks"}
}
},
{
$sort: { totalTasks: -1 }
}
As long as your scale is not too big this way is fine.