MongoDB aggregate and get mismatched results - node.js

Hi everyone i have 2 collections named "members" and "offers" in mongoDB. When a member send an offer to another, my web service saves it to offers collection.
"members" collection is like:
[
{
"_id": "5ee00pp0ebfd4432145233344",
"Fname": "John",
"Lname": "Lastname",
"Email": "JohnLastName#gmail.com",
},
{
"_id": "yyyy44p0ebfd4432145233355",
"Fname": "Ashley",
"Lname": "Lastname",
"Email": "AshleyLastName#gmail.com",
},
{
"_id": "yyyy44p0ebfd4432145233355",
"Fname": "Sue",
"Lname": "Lastname",
"Email": "SueLastName#gmail.com",
}
]
when John send an offer to Ashley
"offers" collection is like:
[
{
"_id": "5eea6e62881835271415fd25",
"OfferMail": "JohnLastName#gmail.com",
"Email": "AshleyLastName#gmail.com",
}
]
Now my question is: How can i get all members except Ashley?

Use the $not operator. For example
db.members.find({"Email" : {"$not" : "AshleyLastName#gmail.com"}})

db.members.aggregate([
{
"$lookup": {
"from": "offers",
"localField": "Email",
"foreignField": "Email",
"as": "docuentInB"
}
},
{
$match: {
$expr: { $eq: [{ $size: "$docuentInB" }, 0 ] }
}
},
{
$project: {
docuentInB: 0
}
}
])````

Related

mongodb aggregate on array of objects

I'm trying to group my participants array in to such a way that for a single participant I should get all the meeting under that participant in an array.
[
{
"_id": "5fc73e7131e6a20f6c492178",
"participants": [
{
"_id": "5fc74bc5e7c54d0ea8f133ca",
"rsvp": "Yes",
"name": "Participant 1",
"email": "participant1#gmail.com"
},
{
"_id": "5fc74e1254b8d337b4ae36d2",
"rsvp": "Not Answered",
"name": "Participant 2",
"email": "participant2#gmail.com"
}
],
"title": "Meeting 1",
"startTime": "2020-11-01T18:30:00.000Z",
"endTime": "2020-11-03T18:30:00.000Z"
},
{
"_id": "5fc73f1cdfc45d3ca0c84654",
"participants": [
{
"_id": "5fc74bc5e7c54d0ea8f133ca",
"rsvp": "Yes",
"name": "Participant 2",
"email": "participant2#gmail.com"
}
],
"title": "Meeting 2",
"startTime": "2020-11-01T18:30:00.000Z",
"endTime": "2020-11-03T18:30:00.000Z"
}
]
my expected result should be like
[{
"participant": {
"_id": "5fc74bc5e7c54d0ea8f133ca",
"rsvp": "Yes",
"name": "Participant 1",
"email": "participant1#gmail.com"
},
meetings: [{meeting1, meeting2, ...and so on}]
},
{
"participant": {
"_id": "5fc74bc5e7c54d0ea8f133ca",
"rsvp": "Yes",
"name": "Participant 2",
"email": "participant2#gmail.com"
},
meetings: [{meeting2, meeting3, ...and so on}]
}
]
I'm kinda stuck for hours to figure it out. I tried the approach by using $group and $unwind but I was getting participants as an array consisting of a single participant(object). and on that I was unable to run $match to match according to the participant's email because participants field was an array.
I tried this
const docs = await Meeting.aggregate([
{ $unwind: '$participants' },
{
$lookup: {
from: 'participants',
localField: 'participants',
foreignField: '_id',
as: 'participants'
}
},
{ $match },
{ $group: { _id: "$participants", meetings: { $push: "$$ROOT" } } },
]);
but this is not matching the expected result which I want it to be.
You can unwind to deconstruct the array and use group to get your desired output
db.collection.aggregate([
{
"$unwind": "$participants"
},
{
$group: {
_id: "$participants._id",
participants: {
$first: "$participants"
},
meetings: {
"$addToSet": "$title"
}
}
}
])
Working Mongo playground

Mongo db Query to filter nested array of objects in document

I have the following document
{
"userid": "5a88389c9108bf1c48a1a6a7",
"email": "abc#gmail.com",
"lastName": "abc",
"firstName": "xyz",
"__v": 0,
"friends": [{
"userid": "5a88398b9108bf1c48a1a6a9",
"ftype": "SR",
"status": "ACCEPT",
"_id": ObjectId("5a9585b401ef0033cc8850c7")
},
{
"userid": "5a88398b9108bf1c48a1a6a91111",
"ftype": "SR",
"status": "ACCEPT",
"_id": ObjectId("5a9585b401ef0033cc8850c71111")
},
{
"userid": "5a8ae0a20df6c13dd81256e0",
"ftype": "SR",
"status": "pending",
"_id": ObjectId("5a9641fbbc9ef809b0f7cb4e")
}]
},
{
"userid": "5a88398b9108bf1c48a1a6a9",
"friends": [{ }],
"lastName": "123",
"firstName": "xyz",
.......
},
{
"userid": "5a88398b9108bf1c48a1a6a91111",
"friends": [{ }],
"lastName": "456",
"firstName": "xyz",
...
}
First Query
Here I want to get userId from friends array ,which having status equals to "ACCEPT".
ie
[5a88398b9108bf1c48a1a6a9,5a88398b9108bf1c48a1a6a91111]
Second Query
After that, I have to make another query on the same collection to get details of each userid returned in the first query.
final Query will return details of [5a88398b9108bf1c48a1a6a9,5a88398b9108bf1c48a1a6a91111]
both userid ie
[
{
userid" : "5a88398b9108bf1c48a1a6a9",
"lastName" : "123",
"firstName" : "xyz"
},
{
"userid" : "5a88398b9108bf1c48a1a6a91111",
"lastName" : "456",
"firstName" : "xyz"
}
]
I have tried so far with
Users.find ({'_id':5a88389c9108bf1c48a1a6a7,"friends.status":'ACCEPT'}, (error, users) => {})
or
Users.find ({'_id':5a88389c9108bf1c48a1a6a7, friends: { $elemMatch: { status: 'ACCEPT' } } }, (error, users) => {})
Use the aggregation framework's $map and $filter operators to handle the task. $filter will filter the friends array based on the specified condition that the status should equal "ACCESS" and $map will transform the results from the filtered array to the desired format.
For the second query, append a $lookup pipeline step which does a self-join on the users collection to retrieve the documents which match the ids from the previous pipeline.
Running the following aggregate operation will produce the desired array:
User.aggregate([
{ "$match": { "friends.status": "ACCEPT" } },
{ "$project": {
"users": {
"$map": {
"input": {
"$filter": {
"input": "$friends",
"as": "el",
"cond": { "$eq": ["$$el.status", "ACCEPT"] }
}
},
"as": "item",
"in": "$$item.userid"
}
}
} },
{ "$lookup": {
"from": "users",
"as": "users",
"localField": "users",
"foreignField": "userid"
} },
]).exec((err, results) => {
if (err) throw err;
console.log(results[0].users);
});
I did not test it. just for an idea, give it a try and let me know.
db.Users.aggregate(
[
{
$unwind: "$friends"
},
{
$match:{ "$friends.status": "ACCEPT"}
},
{
$project:{ "FriendUserID":"$friends.userid"}
},
{
$lookup:{
from:"Users",
as: "FriendsUsers",
localField: "FriendUserID",
foreignField: "userid"
}
},
{
$project: { FriendsUsers.lastName:1,FriendsUsers.firstName:1 }
}
]
)
filtering nested elements
const products = await Product.aggregate<ProductDoc>([
{
$match: {
userId: data.id,
},
},
{
$project: {
promotions: {
$filter: {
input: '$promotions',
as: 'p',
cond: {
$eq: ['$$p.status', PromotionStatus.Started],
},
},
},
userId: 1,
name: 1,
thumbnail: 1,
},
},
]);
for multiple condition
cond: {
$and: [
{
$eq: [
"$$c.product",
"37sd87hjsdj3"
]
},
{
$eq: [
"$$c.date",
"date-jan-4-2022"
],
}
]
},

How can I query on a referenced field in MongoDB?

I have two collections, users and posts. The relevant parts of a typical document looks like this:
user
{
"_id": "user1",
"name": "Joe",
"age": 20
}
posts
{
"content": "Yo what's up!",
"created": "2018-02-05T05:00:00.000Z",
"author": "user1"
}
I would like to create a query on the posts collection that returns the following:
{
"content": "Yo what's up!",
"created": "2018-02-05T05:00:00.000Z",
"author": {
"name": "Joe",
"age": 20
}
Is there any way to do this in raw MongoDB?
I'm using the MongoDB Node.js client.
Using aggregation with lookup operator.
db.posts.aggregate([
{"$lookup":{
"from":"users",
"localField":"author",
"foreignField":"_id",
"as":"author"
}},
{"$addFields":{
"author": {"$arrayElemAt":["$author",0]}
}}])
db.posts.aggregate(
// Pipeline
[
// Stage 1
{
$lookup: {
"from": "user",
"localField": "author",
"foreignField": "_id",
"as": "authorobj"
}
},
// Stage 2
{
$project: {
content: 1,
created: 1,
author: {
'name': {
"$arrayElemAt": ["$authorobj.name", 0]
},
'age': {
"$arrayElemAt": ["$authorobj.age", 0]
}
},
}
},
]
);

Mongoose Aggregate with Lookup

I have a simple two collections like below :
assignments:
[
{
"_id": "593eff62630a1c35781fa325",
"topic_id": 301,
"user_id": "59385ef6d2d80c00d9bdef97"
},
{
"_id": "593eff62630a1c35781fa326",
"topic_id": 301,
"user_id": "59385ef6d2d80c00d9bdef97"
}
]
and users collection:
[
{
"_id": "59385ef6d2d80c00d9bdef97",
"name": "XX"
},
{
"_id": "59385b547e8918009444a3ac",
"name": "YY"
}
]
and my intent is, an aggregate query by user_id on assignment collection, and also I would like to include user.name in that group collection. I tried below:
Assignment.aggregate([{
$match: {
"topic_id": "301"
}
},
{
$group: {
_id: "$user_id",
count: {
$sum: 1
}
}
},
{
$lookup: {
"from": "kullanicilar",
"localField": "user_id",
"foreignField": "_id",
"as": "user"
}
},
{
$project: {
"user": "$user",
"count": "$count",
"_id": "$_id"
}
},
But the problem is that user array is always blank.
[ { _id: '59385ef6d2d80c00d9bdef97', count: 1000, user: [] } ]
I want something like :
[ { _id: '59385ef6d2d80c00d9bdef97', count: 1000, user: [_id:"59385ef6d2d80c00d9bdef97",name:"XX"] } ]

How to use $lookup on embedded document field in mogodb

Please have a look, your help will be appriciated
var user = new Schema({
name: String,
});
var Comments = new Schema({
title : String
, body : String
,user_id : {type: Schema.Types.ObjectId, ref: 'user' }
, date : Date
});
var blog = new Schema({
author : String
, title : String
, body : String
, date : Date
, user_id :{type: Schema.Types.ObjectId, ref: 'user' }
, comments : [Comments]
});
db.blogs.aggregate([
{ $match : { "_id" : ObjectId("57e3b7f4409d80a508d52769") } },
{ $lookup: {from: "users", localField: "user_id", foreignField: "_id", as: "User"} },
])
this returns
[
{
"_id": "57e3b7f4409d80a508d52769",
"author": "Tariq",
"title": "MyfirstPost",
"body": "This is my first post",
"user_id": "57e3b763f7bc810c08f9467a",
"comments": [
{
"title": "hi",
"body": "again i am commenting on this",
"user_id": "57e3b763f7bc810c08f9467a",
"_id": "57e3c153409d80a508d5276b"
},
{
"title": "hi",
"body": "this is seond comment",
"user_id": "57e3b763f7bc810c08f9467a",
"_id": "57e3c8632ebca0ee0afb2ac6"
}
],
"__v": 0,
"User": [
{
"_id": "57e3b763f7bc810c08f9467a",
"name": "Tariq",
"username": "teekay",
"password": "123456",
"__v": 0
}
]
}
]
this return result by comparing blog table is and user table _id which is fine .. but I want to get userdetail with each comment by using user_id of “comments.user_id” blog collection and “_id” of collection
should be something like this
"_id": "57e3b7f4409d80a508d52769",
"author": "Tariq",
"title": "MyfirstPost",
"body": "This is my first post",
"user_id": "57e3b763f7bc810c08f9467a",
"comments": [
{
"title": "hi",
"body": "again i am commenting on this",
"user_id": "57e3b763f7bc810c08f9467a",
"_id": "57e3c153409d80a508d5276b",
"User": [
{
"_id": "57e3b763f7bc810c08f9467a",
"name": "Tariq",
"username": "teekay",
"password": "123456",
"__v": 0
}
]
},
You can run an aggregation operation of the pipeline:
db.blogs.aggregate([
{ "$unwind": "$comments" },
{
"$lookup": {
"from": "users",
"localField": "comments.user_id",
"foreignField": "_id",
"as": "comments.user"
}
},
{ "$unwind": "$comments.user" },
{
"$group": {
"_id": "$_id",
"author": { "$first": "$author" },
"title": { "$first": "$title" },
"body": { "$first": "$body" },
"comments": { "$push": "$comments" },
"user_id": { "$first": "$user_id" }
}
},
{
"$lookup": {
"from": "users",
"localField": "user_id",
"foreignField": "_id",
"as": "user"
}
},
{ "$unwind": "$user" },
])

Resources