How to skip a document based on condition in mongodb aggregation - node.js

Let say I have a schema of blog post which contain many keys and one of them is author (ObjectId). Now I have an another collection of Block users which contains two keys: userid (ObjectId) and userWhoHasBeenBlocked (ObjectId).
Now in aggregation I want to skip those collection which has a author equals to the userWhoHasBeenBlocked.
My Approch: First level I have a match query which chcecks the country from which the post has been made. Let say there is a key of a country.
After this I have a $lookup query for block user collection as
{ $match: { country: "usa" } },
{
$lookup:
{
from: "ublocks",
let: { whoHasBeenBlocked: "$author", currentUser: userid },
pipeline: [
{
$match:
{
$expr:
{
$and:
[
{ $eq: ["$blockedUser", "$$whoHasBeenBlocked"] },
]
}
}
},
],
as: "isBlocked"
},
}
},
{ $match: { "$author": { $ne: "$isBlocked.userId" } } }
}
after this I have $projection block. this is not working. How to skip a document within aggregation. I also have pagination after this.

Related

How to check reference collection has matched data or not in mongoose?

I have 2 simple collections as below.
Product
Id
name
description
likes
id
userId
productId
Now I want a boolean key if the user liked that product or not.
Expected output:
_id
name
description
hasLiked
I have tried by lookup but it's not working.
.lookup({
from: 'likes',
let: {
productId: "$productId"
},
pipeline: [
{
$match:
{
$expr:
{
$and:
[
{ $eq: ["$productId", "$$_id"] }
]
}
}
}
],
as: "hasLiked"
})
First, you need to fix your lookup,
pass _id in productId key
check userId condition, input your userId
check the product id condition in the expression
.lookup({
from: 'likes',
let: { productId: "$_id" },
pipeline: [
{
$match: {
userId: "" // input your userId
$expr: { $eq: ["$$productId", "$productId"] },
}
}
],
as: "hasLiked"
})
Need to check condition in stage,
$ne to check hasLiked is not equal to [] then true otherwise false
.addFields({
hasLiked: { $ne: ["$hasLiked", []] }
})

Use Mongoose aggregate to retrieve data of array inside of a schema

I have a schema in MongoDB like this.
{
productID:1,
reviews:
[
{
_id:1
likes:[{userID:1},{userID:2}],
dislikes:[{userID:3},{userID:4}],
comment:"first comment"
},
{
_id:2
likes:[{userID:1},{userID:2}],
dislikes:[{userID:3},{userID:4}],
comment:"first comment"
}
]
}
I want to fetch the likes count of a userID of a particular review for example like count of userID 2 of review id 2. I tried to get it with the help of aggregate but got stuck.
this is the code that I tried.
ProductReview.aggregate([
{ $match: { productID: productID } },
{ $match: {reviews._id:_id}}
])
but it looks like I am messing with the mongoose syntax.
To get likes by user on particular reviews then use this query
You will have to pass productID, reviewsID and userID
db.collection.aggregate([
{
$match: {
"productID": 1
}
},
{
$unwind: "$reviews"
},
{
$match: {
"reviews._id": 2
}
},
{
$unwind: "$reviews.likes"
},
{
$match: {
"reviews.likes.userID": 2
}
},
{
$group: {
_id: "$reviews.likes",
count: {
$sum: 1
}
}
},
{
$project: {
_id: 0,
userID: "$_id.userID",
count: 1
}
}
])
Mongo Playground: https://mongoplayground.net/p/wUC5tbnLC47
OLD
This returns for all reviews
Mongo Playground: https://mongoplayground.net/p/Ob5BLCAHrw1
if you want both likes and dislikes of users with one query you can use $facet
Mongo Playground: https://mongoplayground.net/p/LELfQfKjw_h

Mongoose aggregate pipeline date greater than query with bson varible

Actually, I am raising this question after trying previous questions answers. but, I don't find any clue that's why I am asking
Trying to achieve:
In mongoose aggregation, I am using pipeline aggregation to get documents from the collection by the following query
$match: {
$and: [
{
$expr: {
$eq: ["$device_id", "$$device_id"]
}
},
{
date: {
"$gte": "$billing_cycle_startdate",
"$lte": endOfDay
}
}
]
}
billing_cycle_startdate will be : 2020-12-31T00:00:00.000Z by following query
{
$addFields: {
billing_cycle_startdate: {
$concat: [
year, "-", month, "-", "$device_details.billing_cycle"
]
},
}
},
{ $set: { billing_cycle_startdate: { $toDate: "$billing_cycle_startdate" } }},
but this query returns empty results
if I run
{
date: {
"$gte": new Date("2020-12-31T00:00:00.000Z"),
"$lte": endOfDay
}
}
it returns results as expected
is there is any other way to convert 2020-12-31T00:00:00.000Z to queryable format without using new Date() function and also want to know what is the difference between 2020-12-31T00:00:00.000Z and new Date("2020-12-31T00:00:00.000Z")
There is any other way to achieve this query??
Thanks in advance..!
Finally, after a few days of suffering, I found what's wrong with my query
I just forget to use let syntax in my pipeline to specify a variable which is billing_cycle_startdate and forget to use it in the pipeline field stage
The pipeline cannot directly access the input document fields.
Instead, first, define the variables for the input document fields,
and then reference the variables in the stages in the pipeline.
for more: click here
then I changed my query as follows
{
$lookup: {
from: "name",
let: {
device_id: "$budget.device",
billing_cycle_startdate: "$billing_cycle_startdate"
},
pipeline: [
{
$match: {
$and: [
{
$expr: {
$eq: ["$device_id", "$$device_id"]
}
},
{
$and: [
{
$expr: {
$gte: ["$date", "$$billing_cycle_startdate"],
},
},
{
$expr: {
$lte: ["$date", endOfDay],
}
}
]
}
]
}
}
],
as: "dailyenergylogs"
}
},

How to fetch doc on basis of the existence of another document in mongoose?

I have a collection with name post and I have one doc and its replicated doc but in replicated doc we have one field different ,some doc don't have replicated doc and that situation depends on an array field of the doc ,if that field have the userId of user then the replicated doc will exist otherwise it will not exist.
So what I want if the doc array have that id then get the replicated post and if not then original post
I have made the query but showing error I am using $exist in $cond ?
Post.aggregate([
{
$match: {
socomo_visibility: socomoId
}
},
{
$project: {
"post_stream_type": {
$cond: {
if: {
'following_users_list': {
$exist: [userId]
}
},
then: constants.POST_STREAM_TYPE.FOLLOW.value,
else: constants.POST_STREAM_TYPE.SOCIAL_CURRY_CHANNEL.value
}
}
}
}
]
You can check whether your array has some value in the boolean-expression in such way:
Do intersection of array and value using $setIntersection.
Check size of that intersection array using $size.
If the size is greater than 0 then value is present in the array. $gt will do this check.
Try the following code:
Post.aggregate([
{
$project: {
"post_stream_type": {
$cond: {
if: {$gt: [{$size: {$setIntersection: ["$following_users_list", [userId]] } }, 0] },
then: constants.POST_STREAM_TYPE.FOLLOW.value,
else: constants.POST_STREAM_TYPE.SOCIAL_CURRY_CHANNEL.value
}
}
}
}
])
okay finally I have done this without using the aggregation .
my answer for the query is
Post.find({
$or: [{
socomo_visibility: {
$elemMatch: {
$eq: socomoId
}
},
post_stream_type: constants.POST_STREAM_TYPE.SOCIAL_CURRY_CHANNEL.value,
following_users_list: {
$exists: true,
$nin: [userId]
}
},
{
socomo_visibility: {
$elemMatch: {
$eq: socomoId
}
},
post_stream_type: constants.POST_STREAM_TYPE.FOLLOW.value,
following_users_list: {
$elemMatch: {
$eq: userId
}
}
}]
})

How to query nested array

Let's say I have documents like
{
name: "name1",
friends: [
{
name: "name2",
thingsWeDo: [
{
name: "running",
like_it: true
},
{
name: "swimming",
like_it: false
}
]
}
]
}
So if I want to know the name of my friend we both love swimming, how do I do it?
I know the schema design could be better, but if I want to query this schema, how do I do it?
is it possible to chain $elemMatch ?
You should $unwind friends and thingsWeDo in aggregation and then use $match to match your criteria. Check below query :
db.collectionName.aggregate({
"$unwind": "$friends" // first unwind friends array
}, {
"$unwind": "$friends.thingsWeDo" // second unwind friends.thingsWeDo
}, {
"$match": {
"friends.thingsWeDo.name": "swimming", // match your criteria
"friends.thingsWeDo.like_it": false
}
}, {
"$project": {
"name": "$friends.thingsWeDo.name",
"like_it": "$friends.thingsWeDo.like_it"
}
}).pretty()
here unwind two times for large documents query will be slow down. As per my recommendation you should change your schema structure and try to avoid unwinding
Untested, but something like this should do:
Model.find({
$and: [
{ "friends.thingsWeDo.name": 'swimming' },
{ "friends.thingsWeDo.like_it": true }
]
}, function (err, docs) {
});

Resources