lookup array shows no result - node.js

i am building an apllication with mongoose and node.js that enables you to post, comment, and like both the posts and the comments.
those are my schemas and the query that i am trying to built to send the user using the apllication all the posts, comments, likes to both the comment section and the post section.
tried to use lookup with mongoose to get comments (and to them likes),but the the pogram shows me no result as can you see:
( i checked by the way .)
comment.js
const commentSchema=
new mongoose.Schema({
userID : {type: mongoose.Types.ObjectId, ref: "User",required: true },
content : {type: String,required: true },
date :{type : Date,default:()=>Date.now()} ,
})
module.exports=mongoose.model("comment",commentSchema)
likes.js
const LikesSchema= new mongoose.Schema({
userID : {type: mongoose.Types.ObjectId, ref: "user",required: true },
postCommentID : {type: mongoose.Types.ObjectId ,required: true } //can be both a comment or a post
})
module.exports=mongoose.model("likes",LikesSchema)
posts.js
const postSchema= new mongoose.Schema({
userID : {type: mongoose.Types.ObjectId, ref: "User",required: true },
content : {type: String,required: true },
date : {type : Date,default:()=>Date.now()},
commentsID :[{type:mongoose.Types.ObjectId, ref:'comment' }],
})
module.exports=mongoose.model("post",postSchema)
incomplete query
Query.js
post.aggregate(
[
{
$lookup: {
from: 'likes',
localField: '_id',
foreignField: 'postCommentID',
as: '_likes'
},
},
{
//NOT WORKING
$lookup: {
from: 'comment',
localField : 'commentsID',
foreignField : '_id',
as: 'comments'
},
},
{
$set: {
'likes': '$_likes.userID'
}
},
{
$project: {
'_likes': 0,
}
},
]
)
result:
as can you see the comment section is empty.
[{
_id: new ObjectId("621fdff521935fad17cc27b5"),
userID: new ObjectId("621ba7b84ade9cd7ebe7ef46"),
content: 'new post',
commentsID: [
new ObjectId("621fe07c21935fad17cc29f9"),
new ObjectId("621fe2b221935fad17cc2aef"),
new ObjectId("621fe2ff21935fad17cc2b45"),
new ObjectId("621fe83260288e8ee9db1d62"),
new ObjectId("621fe9361ab243a8c2ebb0eb"),
new ObjectId("621ff5d471b483d2f59ca493")
],
date: 2022-03-02T21:21:57.660Z,
__v: 0,
comments: [],
likes: [
new ObjectId("621fe07c21935fad17cc29f9"),
new ObjectId("621fe2b221935fad17cc2aef"),
new ObjectId("621fe2ff21935fad17cc2b45")
]
}
]

Related

how to sort after lookup and project aggregation in mongodb?

I have 2 Collections one for users and other for posts(Posts colllection have _id of users as postedBy).
In users collection each user is having friends array which have _id of users in it.I want to get all the Posts of My friends and mine post in sorted order(sorted By CreatedAt).
This is my Userschema in which i am having friends array of mongoose object type ref to user collection,
here i'm storing users id who is friend.
`//UserSchema
const userSchema = new Schema({
profileImg : {
type: String,
},
name: {
type: String,
required: [true, 'Please Enter Your Name!']
},
about: {
type: String,
},
email: {
type: String,
required: [true, 'Please Enter Email!'],
unique: [true, 'Already Registered!'],
match: [/\S+#\S+\.\S+/, 'is invalid!']
},
password: {
type: String,
required: [true, 'Please Enter Your Password!'],
},
friends: [{
type: mongoose.Types.ObjectId,
ref: 'USER'
}],
address: {
line1: {
type: String,
required: [true, 'Please Enter Your Address!']
},
line2: {
type: String
},
city: {
type: String,
required: [true, 'Please Enter Your City!']
},
state: {
type: String,
required: [true, 'Please Enter Your State!']
},
}
}, { timestamps: true })
This is my Post Schema where userId is ref to users collection and here the _id of user who is uploading post is saved.
//POST SCHEMA
const postSchema = new Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "USER",
required: true
},
postImage: {
type: String,
required: [true, 'Please Upload the Image!']
},
caption: {
type: String
},
likes: [likeSchema],
comments: [commentSchema]
}, { timestamps: true })
`
What I am Doing:
1st I am finding the user through _id
2nd from found user's friend array ,lookup in posts collection to get post of friends
3rd Now to get owns post again look up in post collection with own _id
4th concat the both array obtain from friend post and user post as Posts
Now here after step 4 i want to sort the Posts by createdAt but its not working..
How to sort it?
const posts = await User.aggregate([
{
$match: {
_id: mongoose.Types.ObjectId(req.user_id)
}
},
{
$lookup: {
from: "posts",
localField: "friends",
foreignField: "userId",
as: "friendposts"
}
},
{
$lookup: {
from: "posts",
localField: "_id",
foreignField: "userId",
as: "userposts"
}
},
{
$project: {
"Posts": {
$concatArrays: ["$friendposts", "$userposts"]
},
_id: 0
}
}
])
you can use 1 lookup instead of 2 .
for sorting you have 3 ways
sort in the code level (using sort function)
use $unwind $sort and group (if mongo db version is less than 5.2)
use $sortArray (applicable for mongodb version 5.2+)
if using 2nd method.
User.aggregate([
{
'$match': {
'_id': mongoose.Types.ObjectId(req.user_id)
}
}, {
'$addFields': {
'users': {
'$concatArrays': [
'$friends', [
mongoose.Types.ObjectId(req.user_id)
]
]
}
}
}, {
'$lookup': {
'from': 'posts',
'localField': 'users',
'foreignField': 'userId',
'as': 'posts'
}
}, {
'$unwind': {
'path': '$posts'
}
}, {
'$sort': {
'posts.createdAt': -1
}
}, {
'$group': {
'_id': '$_id',
'posts': {
'$push': '$posts'
},
'name': {
'$first': '$name'
}
}
}
])
you can add any other field needed in final response like wise i added name .

How to populate the result of a $lookup

I have 3 collections, posts, comments and users, the schemas for posts and comments are below:
post schema
const PostSchema: Schema = new Schema({
author: { type: String, ref: 'User' },
postID: {type: String},
text: { type: String },
});
comment schema
const commentSchema: Schema = new Schema({
author: { type: Schema.Types.ObjectId, ref: 'User' },
parentPost: {type: Schema.Types.ObjectId, ref: 'Post'},
parentPostID: {type: String}, // Post that was commented on
});
To get the comment from each post, I do an aggregate query:
const aggregateQuery = [
{
$match:{postID:{ $in: postKeys},},
},
{
$lookup:
{
from: 'comments',
localField: '_id',
foreignField: 'parentPost',
as: 'Top_Comment',
},
},
{
$sort: {
createdAt: 1,
}
,
},
]
That query works, but I can't figure out how to populate the author property of the comment since its a ref to a user.
What I tried
I tried using pipeline, but I'm a new to aggregation so I didn't know how, any ideas and solutions would be really appreciated

Include count of subdocuments in schema

In my NodeJS project, I'm creating Mongoose schemas as below:
//Likes Schema
var likesSchema = mongoose.Schema({
postId: { type: mongoose.Schema.Types.ObjectId, ref: "Post", required: 'Provide the news ID to which this comment belongs' },
});
module.exports = mongoose.model('Likes', likesSchema);
//Post schema
var postSchema = mongoose.Schema({
title: { type: String, required: 'Kindly enter the title' },
description: { type: String, required: 'Kindly enter the description of the news' }
});
module.exports = mongoose.model('Post', postSchema);
Post is a schema that has a title and a description. Like is a schema that tracks number of likes for a particular post. So it has just postID.
Now I want to include "count" of likes as a variable in "Post" schema. I don't want to count the likes during query execution.
Is there any simple way to achieve it?
I found a solution after doing some trial and errors:
db.Post.aggregate([
{
$lookup: {
from: "Likes",
localField:"_id",
foreignField: "postId",
as: "likes"
}
},
{
$project: {
title: 1,
description: 1,
count: { $size: "$likes" }
}
}
]).pretty()

mongoose aggregation not returning expected result

I am currently learning aggregation and some related methods, after following mongoose and mongodb docs i tried it. but i am having problem.
Follow.aggregate([
{ $match: { user: mongoose.Types.ObjectId(userId) } },
{ $unwind: '$followers' },
{
$lookup: {
from: 'accounts',
localField: 'followers',
foreignField: '_id',
as: 'followers'
}
},
{ $project: { name: 1, photo: 1 } },
]).exec((err, followers) => {
if (err) throw err;
console.log(followers);
res.send(followers);
});
I want to get the followers of that userID and select the followers names and photo, but i am only getting the objectid of the matched document
[ { _id: 5bfe2c529419a560fb3e92eb } ]
expected output
[ { _id: 5bfe2c529419a560fb3e92eb , name: 'john doe", photo: 'cat.jpg'} ]
Follow Model
const FollowSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'Account',
required: true,
},
following: [{
type: Schema.Types.ObjectId,
ref: 'Account',
required: true,
}],
followers: [{
type: Schema.Types.ObjectId,
ref: 'Account',
required: true,
}],
});
When the $project stage is wrong you would get that result. Try removing it first and see the output. To me it seems you should have something like this there:
{ $project: { "followers.name": 1, "followers.photo": 1 } },

Populate Virtuals - populate the existing array its referencing .

Is it possible to use mongoose's Populate Virtuals to populate the array of values it is referencing?
User Model
var userSchema = new mongoose.Schema({
auth_key: {type: String},
channels: [{
name: {type: String},
last_access: { type: Date, default: Date.now },
status: {type: String, default: false },
new_messages: {type: Number},
user_channel_group: {type: String}
}]
}, {
toJSON: {
virtuals: true
}
});
userSchema.virtual('channels.details', {
ref: 'channel',
localField: 'channels.name',
foreignField: 'name'
});
var user = mongoose.model('user', userSchema, 'user');
Channel Model
var channelSchema = new mongoose.Schema({
name: {type: String, required: true},
members: [{ type: String, required: true }],
displayName: {type: String},
type: {type: Number},
create_at: {type: Date, default: Date.now}
});
var channel = mongoose.model('channel', channelSchema, 'channel');
My query that I am using I want the virtual to present the channel details from each channel alongside the channels a user is subscribed to. so something like this..
[{
"_id": "588a82ff7fe89686fd2210b0",
"channels": [{
"details": {
"_id": "588a80fd7fe89686fd2210a8",
"name": "channel1",
"members": []
},
"name": "channel1"
}, {
"details": {
"_id": "588a80fd7fe89686fd2210a9",
"name": "channel2",
"members": []
},
"name": "channel2"
}],
"id": "588a82ff7fe89686fd2210b0"
}
...
]
My Query for this is ..
user.find({}).populate('channels.details').exec()

Resources