Display only select nested fields of object in MongoDB Compass aggregation - mongodb

I have the following data model:
{
"_id": {
"$oid": "63b6da81661f0ecd23cd9830"
},
"Plan": [
{
"_id": {
"$oid": "63b6311e0871625f7ceb85ad"
},
"Name": "Straight ankle lock",
"Date": {
"$date": {
"$numberLong": "1672725600000"
}
},
"Notes": "Christian taught ankle locks",
"TeamId": {
"$oid": "63a291ebb60592854e23b8fb"
}
}
],
"User": [
{
"_id": {
"$oid": "6240fd2ee1335b45680bee9d"
},
"FirstName": "Test",
"LastName": "User",
"TeamId": {
"$oid": "639fd03bb31c7995a9d4b28c"
}
}
]
}
And I'd like to show a new object via aggregation that looks like:
{
"_id": {
"$oid": "63b6da81661f0ecd23cd9830"
},
"PlanName": "Straight ankle lock",
"UserName": "Test User"
}
I've been trying to figure this out for a few days, but at this point not sure if it is even possible. Any ideas?
Thanks.
Newer model based on Ray's input using project:
{
"_id": {
"$oid": "63b6da81661f0ecd23cd9830"
},
"InsertDate": {
"$date": {
"$numberLong": "1672927873507"
}
},
"Plan": {
"Name": "Straight ankle lock"
},
"User": {
"FirstName": "Adam",
"LastName": "Gusky"
},
"Team": {
"TeamName": "GB2 No Gi"
}
}
The query I'm using to get the above data:
[
{
$lookup: {
from: "Plans",
localField: "PlanId",
foreignField: "_id",
as: "Plan",
},
},
{
$lookup: {
from: "Teams",
localField: "TeamId",
foreignField: "_id",
as: "Team",
},
},
{
$lookup: {
from: "Users",
localField: "UserId",
foreignField: "_id",
as: "User",
},
},
{
$project: {
Plan: {
$first: "$Plan",
},
User: {
$first: "$User",
},
Team: {
$first: "$Team",
},
InsertDate: 1,
},
},
{
$project: {
"Plan.Name": 1,
"User.FirstName": 1,
"User.LastName": 1,
"Team.TeamName": 1,
InsertDate: 1,
},
},
]

You can simply set the value you want in the $project stage.
db.collection.aggregate([
{
$project: {
_id: 1,
PlanName: {
$first: "$Plan.Name"
},
UserName: {
"$concat": [
{
"$first": "$User.FirstName"
},
" ",
{
"$first": "$User.LastName"
}
]
}
}
}
])
Mongo Playground

Related

MongoDB match in aggregation lookup

This is my current query:
db.ministryteams.aggregate([
{
$addFields: {
"id_ministryTeam": { $toObjectId: "$_id" }
}
},
{
$lookup:
{
from: "profiles",
localField: "phone",
foreignField: "phone",
as: "profile"
},
},
{ $unwind: "$profile" },
{
$project: {
"profile._id": 1,
"profile.name": 1,
"profile.phone": 1,
"profile.type": 1,
"profile.contactAllowed": 1,
"profile.createAt": 1,
"id_ministryTeam": 1,
"_id": 0
}
}
])
And currently this query returns two profiles:
[{
"id_ministryTeam": "ObjectId(\"62a79c461df25412ae7ef2ff\")",
"profile": {
"_id": "ObjectId(\"62a798074e105c2b74fe6d81\")",
"name": "Informe seu nome aqui.",
"contactAllowed": true,
"type": "member",
"phone": "16900001111"
}
},
{
"id_ministryTeam": "ObjectId(\"62a79cf21df25412ae7ef311\")",
"profile": {
"_id": "ObjectId(\"62a79cf21df25412ae7ef30e\")",
"name": "Informe seu nome aqui.",
"contactAllowed": true,
"type": "member",
"phone": "16900001112"
}
}]
I would like to bring only one result, the profile._id: "62a798074e105c2b74fe6d81", I made several attempts with the match, but I couldn't get the expected result, if anyone can help me.
Try something like this
db.ministryteams.aggregate([
{
$addFields: {
"id_ministryTeam": { $toObjectId: "$_id" }
}
},
{
$lookup:
{
from: "profiles",
localField: "phone",
foreignField: "phone",
as: "profile"
},
},
{ $unwind: "$profile" },
{ $match: { "profile._id": mongoose.Types.ObjectId("your_ID_here") } },
{
$project: {
"profile._id": 1,
"profile.name": 1,
"profile.phone": 1,
"profile.type": 1,
"profile.contactAllowed": 1,
"profile.createAt": 1,
"id_ministryTeam": 1,
"_id": 0
}
}
])

How can I get a mongo subset of a collection based on an another collection

I have two collections.
Collection 1 is like an account.
Collection 2 creates a unique association between a user and an account
I am trying to return the accounts for which the user has no association
Collection1 schema
const Collection1Schema = new Schema({
name: { type: String, required: true },
});
Collection1 data
[
{
"_id": "61cf8452fca008360872c9cd",
"name": "Aff 2"
},
{
"_id": "61cf845ffca008360872c9d0",
"name": "AFF 1"
},
{
"_id": "61cf8468fca008360872c9d3",
"name": "Aff 3"
}
]
Collection2 schema
const Collection2Schema = new Schema({
userID: { type: Schema.Types.ObjectId, required: true },
col_1_ID: { type: Schema.Types.ObjectId, required: true },
});
Collection2 data
[
{
"_id": "61e05bb5fe1d8327d4c73663",
"userID": "61cf82dac828bd519cfd38ca",
"col_1_ID": "61cf845ffca008360872c9d0"
},
{
"_id": "61e05c14fe1d8327d4c7367d",
"userID": "61cf82dac828bd519cfd38ca",
"col_1_ID": "61cf8468fca008360872c9d3"
},
{
"_id": "61e05ca0fe1d8327d4c73695",
"userID": "61e05906246ccc41d4ebd30f",
"col_1_ID": "61cf8452fca008360872c9cd"
}
]
This is what I have so far... but it does not return what the user is NOT apart of
I am using Collection2 as the basis in the pipeline
[
{
'$match': {
'userID': new ObjectId('61cf82dac828bd519cfd38ca')
}
}, {
'$lookup': {
'from': 'Collection1',
'localField': 'col_1_ID',
'foreignField': '_id',
'as': 'aa'
}
}, {
'$unwind': {
'path': '$aa',
'preserveNullAndEmptyArrays': true
}
}
]
What I would like to return is all the collection 1 documents ( where userIdD = '61cf82dac828bd519cfd38ca') is NOT associated in collection 2 ... like this :
[
{
"_id": "61cf8452fca008360872c9cd",
"name": "Aff 2"
}
]
UPDATE 1
Here is a playground where another user has joined another account, so the pipeline does not return "Aff 2" like expected
https://mongoplayground.net/p/W6W88_2MaI3
UPDATE 2
Here is a playground that almost does what I want... it's returning duplication "AFF 2" entries.
https://mongoplayground.net/p/nTI3MKNPEmD
try the inversing lookup
https://mongoplayground.net/p/hXAYyv8X461
db.Collection1.aggregate([
{
"$lookup": {
"from": "Collection2",
"localField": "_id",
"foreignField": "col_1_ID",
"as": "joined_docs"
}
},
{
$unwind: {
"path": "$joined_docs"
}
},
{
$match: {
"joined_docs.userID": {
$ne: "61cf82dac828bd519cfd38ca"
}
}
},
{
$project: {
"joined_docs": 0
}
}
])
ANSWER:
after messing around with several mongo playgrounds and digging into a few different pipeline attributes... here is what works:
https://mongoplayground.net/p/xbZeRfVcrZq
Data:
db={
"Collection1": [
{
"_id": "61cf8452fca008360872c9cd",
"name": "Aff 2"
},
{
"_id": "61cf845ffca008360872c9d0",
"name": "AFF 1"
},
{
"_id": "61cf8468fca008360872c9d3",
"name": "Aff 3"
}
],
"Collection2": [
{
"_id": "61e05bb5fe1d8327d4c73663",
"userID": "61cf82dac828bd519cfd38ca",
"col_1_ID": "61cf845ffca008360872c9d0"
},
{
"_id": "61e05c14fe1d8327d4c7367d",
"userID": "61cf82dac828bd519cfd38ca",
"col_1_ID": "61cf8468fca008360872c9d3"
},
{
"_id": "61e05ca0fe1d8327d4c73695",
"userID": "61e05906246ccc41d4ebd30f",
"col_1_ID": "61cf8452fca008360872c9cd"
},
{
"_id": "61e05c14fe1d8327d4c73600",
"userID": "61cf82dac828bd519cfd3111",
"col_1_ID": "61cf8468fca008360872c9d3"
},
{
"_id": "61e05c14fe1d8327d4c73601",
"userID": "61cf82dac828bd519cfd3112",
"col_1_ID": "61cf8452fca008360872c9cd"
},
]
}
Pipeline:
db.Collection1.aggregate([
{
"$lookup": {
"from": "Collection2",
"localField": "_id",
"foreignField": "col_1_ID",
"as": "joined_docs"
}
},
{
$match: {
"joined_docs.userID": {
$ne: "61cf82dac828bd519cfd38ca"
}
}
},
{
$unwind: {
"path": "$joined_docs",
}
},
{
$group: {
_id: "$_id",
"name": {
"$first": "$name"
},
}
}
])
result:
[
{
"_id": "61cf8452fca008360872c9cd",
"name": "Aff 2"
}
]
try this instead:
https://mongoplayground.net/p/HDm2sbdvH88
db.Collection1.aggregate([
{
"$lookup": {
"from": "Collection2",
"localField": "_id",
"foreignField": "col_1_ID",
"as": "joined_docs"
}
},
{
$unwind: {
"path": "$joined_docs"
}
},
{
$group: {
_id: {
account_id: "$_id",
account_name: "$name",
},
user_ids: {
$push: {
"userID": "$joined_docs.userID"
}
}
}
},
{
$match: {
"user_ids.userID": {
$nin: [
"61cf82dac828bd519cfd38ca"
]
}
}
},
{
$project: {
user_ids: 0
}
}
])

Group documents from multiple collections by date

I have 3 schema with a basic structure
meal: {
user: 'objectID',
createdAt: 'date
}
activity: {
user: 'objectID',
createdAt: 'date'
}
role: {
user: 'objectID',
createdAt: 'date'
}
I would like to get all documents from each schema belonging to a user and group them by dates. For example, a response of
history: [
{
date: 01-11-2021,
meal: [
...array of meal documents on 01-11-2021
],
activity: [
...array of meal documents on 01-11-2021
],
role: [
...array of meal documents on 01-11-2021
],
},
...next date
]
data
db={
"user": [
{
"_id": 1,
"name": "Sam"
}
],
"meal": [
{
"user": 1,
"content": "apple",
"createdAt": ISODate("2021-09-01T11:23:25.184Z")
},
{
"user": 1,
"content": "orange",
"createdAt": ISODate("2021-09-01T11:23:25.184Z")
},
{
"user": 1,
"content": "pie",
"createdAt": ISODate("2021-09-02T11:23:25.184Z")
}
],
"activity": [
{
"user": 1,
"content": "baseball",
"createdAt": ISODate("2021-09-01T11:23:25.184Z")
}
],
"role": [
{
"user": 1,
"content": "admin",
"createdAt": ISODate("2021-09-01T11:23:25.184Z")
}
]
}
aggreagte
db.user.aggregate([
{
"$match": {
_id: 1
}
},
{
"$lookup": {
"from": "meal",
"localField": "_id",
"foreignField": "user",
"pipeline": [
{
"$set": {
"from": "meal"
}
}
],
"as": "meal_docs"
}
},
{
"$lookup": {
"from": "activity",
"localField": "_id",
"foreignField": "user",
"pipeline": [
{
"$set": {
"from": "activity"
}
}
],
"as": "activity_docs"
}
},
{
"$lookup": {
"from": "role",
"localField": "_id",
"foreignField": "user",
"pipeline": [
{
"$set": {
"from": "role"
}
}
],
"as": "role_docs"
}
},
{
$project: {
user: "$name",
items: {
$concatArrays: [
"$activity_docs",
"$meal_docs",
"$role_docs"
]
}
}
},
{
"$unwind": "$items"
},
{
$project: {
createdAt: {
$dateTrunc: {
"date": "$items.createdAt",
"unit": "day"
}
},
content: "$items.content",
from: "$items.from"
}
},
{
"$group": {
"_id": {
"createdAt": "$createdAt",
"from": "$from"
},
"list": {
"$push": "$$ROOT.content"
}
}
},
{
"$group": {
"_id": "$_id.createdAt",
"documents": {
"$push": {
k: "$$ROOT._id.from",
v: "$$ROOT.list"
}
}
}
},
{
"$project": {
documents: {
$arrayToObject: "$documents"
}
}
},
{
"$group": {
"_id": 1,
"history": {
"$push": {
date: "$$ROOT._id",
activity: "$$ROOT.documents.activity",
meal: "$$ROOT.documents.meal",
role: "$$ROOT.documents.role"
}
}
}
}
])
mongoplayground

Referring to a different collection from an existing one and counting from the same collection

I have to collections A and B in which the documents of A contains the object ids which are present in the B in the fields centre and gcentre. What I'm currently is outputting the result which contains the name of the parent centre by referring from collection A's object id to B and then referring the gcentre's id to find the child and centre and count the documents assigned via javascript post-processing. Been new to the aggregation pipeline, I don't know how to refer via object id and that sort of counting of records. Is it possible with the aggregation pipeline? I have tried with $lookup but it doesn't seem to give the output as expected.
Documents in collection A:
{
"_id": {
"$oid": "5bbafa98d8c77251bea30f8c"
},
"parentCentre": {
"$oid": "1cbafa99d8c77251bea30f11"
},
"childCentre": {
"$oid": "5cbafa99d8c77251bea30f8d"
},
},
{
"_id": {
"$oid": "5bbafa98d8c77251bea30f8c"
},
"parentCentre": {
"$oid": "1cbafa99d8c77251bea30f11"
},
"childCentre": {
"$oid": "5cbafa99d8c77251bea30f8d"
},
},
{
"_id": {
"$oid": "5bbafa98d8c77251bea30f8c"
},
"parentCentre": {
"$oid": "1cbafa99d8c77251bea30f11"
},
"childCentre": {
"$oid": "5cbafa99d8c77251bea30f8d"
},
},
{
"_id": {
"$oid": "5bbafa98d8c77251bea30f8c"
},
"parentCentre": {
"$oid": "1cbafa99d8c77251bea30f21"
},
"childCentre": {
"$oid": "5cbafa99d8c77251bea30f6d"
},
}
Documents in collection B:
{
"_id": {
"$oid": "1cbafa99d8c77251bea30f11"
},
"Type": "Parent",
"Name": "Kris Labs"
},
{
"_id": {
"$oid": "1cbafa99d8c77251bea30f21"
},
"Type": "Parent",
"Name": "DEX Labs"
},
{
"_id": {
"$oid": "5cbafa99d8c77251bea30f8d"
},
"Type": "Child",
"Name": "Mili Labs"
},
{
"_id": {
"$oid": "5cbafa99d8c77251bea30f6d"
},
"Type": "Child",
"Name": "Max Labs"
}
Result:
{
"parentCentreName":"Kris Labs",
"Records":{
{
childCentreName: "Max Labs",
recordCount: 3
}
}
},
{
"parentCentreName":"DEX Labs",
"Records":{
{
childCentreName: "Mili Labs",
recordCount: 1
}
}
}
You can use the following aggregation query:
db.A.aggregate([
{
$group: {
_id: {
p: "$parentCentre",
c: "$childCentre"
},
count: {
$sum: 1
}
}
},
{
$group: {
_id: "$_id.p",
Records: {
$push: {
childCentreName: "$_id.c",
recordCount: "$count"
}
}
}
},
{
$unwind: "$Records"
},
{
"$lookup": {
"from": "B",
"localField": "_id",
"foreignField": "_id",
"as": "p"
}
},
{
"$lookup": {
"from": "B",
"localField": "Records.childCentreName",
"foreignField": "_id",
"as": "c"
}
},
{
$unwind: "$c"
},
{
$unwind: "$p"
},
{
$project: {
"parentCentreName": "$p.Name",
"Records.childCentreName": "$c.Name",
"Records.recordCount": 1,
_id: 0
}
},
{
$group: {
_id: "$parentCentreName",
"Records": {
$push: "$Records"
}
}
},
{
$project: {
"parentCentreName": "$_id",
"Records": 1,
_id: 0
}
}
])
MongoDB Playground

Aggregation on multiple collections with key in localfield

I have three collections which are inter-related
Partner
{
"_id": "5d68b91f0ef87f0c36ad1f7b",
"name": "1111 Vijay Dev",
}
Event {
"oneTime": true,
"_id": "5d6cfc09967a6f45c51d4375",
"title": "WelcomeOneEvent1",
}
User which contains data for both Partner and Event with Keys partnerId and eventId
{
"_id": ObjectId("5d68f06e3058326af09d6c53"),
"firstName": "Demo",
"partners": [
{
"_id": ObjectId("5d6cafd3e109107b83068657"),
"partnerId": ObjectId("5d4d60d6f45f1c6e723bc074")
}
],
"events": [
{
"_id": ObjectId("5d6cfc18967a6f45c51d437b"),
"eventId": ObjectId("5d6a4b882d267958eb82071c")
},
{
"_id": ObjectId("5d6cfc18967a6f45c51d437a"),
"eventId": ObjectId("5d6cfc09967a6f45c51d4375")
}
]
}
I need to get the list of all partners with users and events of those users.
I tried fetching the partners array along with users and it was successful but I am unable to fetch events detail. Below is my code for same
partnerSchema.statics.chking = function() {
return new Promise((resolve, reject) => {
this.aggregate(
[
{
$lookup: {
from: 'users',
localField: '_id',
foreignField: 'partners.partnerId',
as: 'users'
}
},
{
$unwind:{
'path': '$user.events',
'preserveNullAndEmptyArrays': true
}
},
{
$lookup: {
from: 'events',
localField: 'users.events.eventId',
foreignField: '_id',
as: 'events'
}
},
{
$project: {
name: 1,
'users._id': 1,
'users.firstName': 1,
'users.events': '$events'
}
}
],
function(err, result) {
console.log('result', result)
if (err) return reject(err)
resolve(result)
}
)
})
}
Actual result is something like this. I need to add the missing events detail like id and title:
{
"data": [
{
"_id": "5d68b91f0ef87f0c36ad1f7b",
"name": "1111 Vijay Dev",
"users": [
{
"_id": "5d6a144f498ea95bf51298ea",
"firstName": "Vijay one",
"events": []
},
{
"_id": "5d6a1459498ea95bf51298ec",
"firstName": "vijay 2",
"events": []
},
{
"_id": "5d6d046c0b6700548397e262",
"firstName": "check11",
"events": []
}
]
}
]
}
Expected:
{
"data": [
{
"_id": "5d68b91f0ef87f0c36ad1f7b",
"name": "1111 Vijay Dev",
"users": [
{
"_id": "5d6a144f498ea95bf51298ea",
"firstName": "Vijay one",
"events": [
{ "_id": "5d6cfc09967a6f45c51d4374",
"title": "WelcomeOneEvent1"},
{ "_id": "5d6cfc09967a6f45c51d4375",
"title": "WelcomeTwoEvent2"},
]
},
{
"_id": "5d6a1459498ea95bf51298ec",
"firstName": "vijay 2",
"events": []
},
{
"_id": "5d6d046c0b6700548397e262",
"firstName": "check11",
"events": []
}
]
}
]
}
Please try this :
Partner.aggregate([
{
$lookup: {
from: 'users',
localField: '_id',
foreignField: 'partners.partnerId',
as: 'users'
}
},
{
$unwind: {
'path': '$users',
'preserveNullAndEmptyArrays': true
}
},
{
$lookup: {
from: 'events',
localField: 'users.events.eventId',
foreignField: '_id',
as: 'events'
}
}, { $addFields: { 'users.events': '$events' } }, { $group: { _id: '$_id', users: { $push: '$users' }, data: { $first: '$$ROOT' } } }, { $addFields: { 'data.users': '$users' } },
{ $replaceRoot: { 'newRoot': '$data' } }, {
$project: {
name: 1,
'users._id': 1,
'users.firstName': 1,
'users.events': 1
}
}
])