Use Mongoose aggregate to retrieve data of array inside of a schema - node.js

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

Related

I have Error Called Arguments must be aggregate pipeline operators

I have some issues with MongoDB aggregate in node.js
Error: Arguments must be aggregate pipeline operators
This is my code
let find_result = await Users.aggregate([
{ $sample: { size: 10 } },
{ $group: { _id: '$_id'} },
{ $project: {
_id : {
$nin: arr2
}
}},
{ $unwind: '$_id' }
])
This code is to output randomly without duplication except for yourself and the person you choose (arr2 contains your _id and the _id of the person you choose)
Remove the comma before unwind.
let find_result = await Users.aggregate([
{ $sample: { size: 10 } }
,{ $group: { _id: '$_id'} },
{ $project: {
"_id" : {
$nin: arr2
}
}
},
{ $unwind: '$_id' },
])

Select Max of A field from a table in Mongo

I want to write the SQL statement that will select the Max of Reported and also add another column Commodity_Code then group by Commodity_Code as shown below in Mongo:
SELECT Commodity_Code as commodity_code, MAX(Reported_Date) as reported_date FROM marketstates WHERE State_Name='Gujarat'
GROUP BY Commodity_Code ORDER BY Reported_Date ASC;
I was able to write the code below in Mongo but not convinced it is what I want:
db.market_state.aggregate([{$match: {State_Name: {$eq: 'Gujarat'} }}, {$group: {_id: "$Commodity_Code", reported_date: {$max: "$Reported_Date_str"}}}, {$sort: {"Reported_Date_str": -1}} ])
Kindly point out what I am doing wrong.
Your code works fine.
db.collection.aggregate([
{
$match: {
State_Name: { $eq: "Gujarat" }
}
},
{
$group: {
_id: "$Commodity_Code",
reported_date: { $max: "$Reported_Date_str" }
}
},
{
$sort: { "Reported_Date_str": -1 }
},
{
$set: { "commodity_Code": "$_id" }
}
])
mongoplayground

Mongodb aggregate pipeline for matching a reference model's field name of a sub document in a collection

I have two collections one is Product and another is Stores
prouduct1 = {
name: "chair",
code: 034,
};
product2 = {
name: "table",
code: 035,
};
During material entry, Stores model is updated with following schema
goodsReceipt = {
invoicenumber: 2,
products: [
{ product: "ObjectId(product1)", qty: 15 },
{ product: "ObjectId(product2)", qty: 20 },
],
};
Now, i would like to go through entire store's register and matching product 1 id and then find out sum of all its qty.
You can use below aggregation
import mongoose from "mongoose";
db.stores.aggregate([
{ $match: { "products.product": mongoose.Types.ObjectId(productId) }},
{ $unwind: "$products" },
{ $match: { "products.product": mongoose.Types.ObjectId(productId) }},
{ $group: {
_id: null,
qty: { $sum: "$products.qty" }
}}
])

How to skip a document based on condition in mongodb aggregation

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.

Get only the last element of array mongoose

I have array in a document, and I try to receive the last element of this array.
My code is:
Post.find({_id:postId},{'comments':{'$slice':-1}});
this gives me all the object but the comments array contains only the last element.
on the other hand,
Post.find({_id:postId},{'comments':1});
give me only the comments.
I dont find how to combine the two commands together. How it can be done?
{
"users":[],
"comments":["string1","string2","string3"],
"lastValue":"Wow"
"name":"jow"
"_id": {
"$oid": "5747d6bdecfae9d0560077cc"
},
}
Thanks
You might want to use mongodb (version 3.2) aggregation $slice like that:
Post.aggregate([
{
$match: {
'_id.$oid': postId
}
},
{
$project: {
comments: {
$slice: [ "$comments", -1 ]
}
}
}
]);
In earlier versions of mongodb:
Post.aggregate([
{
$match: {
'_id.$oid': postId
}
},
{
$unwind: "$comments"
},
{
$group : {
_id: "$_id.$oid",
comment: { $last: "$comments" }
}
}
]);
I hope this helps.
db.Post.find(
{ _id: postId },
{ comments: { $slice: -1 }, _id: 0, users: 0, lastValue: 0, name: 0 },
);
In case of Mongoose, slice can work this way also,
model.find({
// condition
})
.select('fields')
.slice('array', -1) // <------ Here
.then((data) => {
// handle
})
.catch();
Just wrote pseudo code, as it might help someone.
db.collection_name.find({'name':'how'},{'comments': {$slice: -1}})

Resources