MongoDB unknown top level operator - mongodb

Well I'm having problems with aggragate of the mongo, I need to validate if in all the answers it doesn't have a field marked as deletedAt. My aggragate looks like this:
[
{ '$match': { _id: "5f0cc0e676de351ce21a752b" } },
{
'$lookup': {
from: 'Exams',
localField: 'exams.idExams',
foreignField: '_id',
as: 'exams'
}
},
{
'$lookup': {
from: 'Sports',
localField: 'idSports',
foreignField: '_id',
as: 'sportPracticed'
}
},
{
'$unwind': { path: '$sportPracticed', preserveNullAndEmptyArrays: true }
},
{
'$lookup': {
from: 'Galery',
localField: '_id',
foreignField: 'idPlayer',
as: 'galery'
}
},
{
'$lookup': {
from: 'EvaluationPlayer',
localField: '_id',
foreignField: 'idPlayer',
as: 'evaluationPlayer'
}
},
{
'$lookup': {
from: 'Evaluation',
localField: 'evaluationPlayer.idEvaluation',
foreignField: '_id',
as: 'evaluations'
}
},
{
'$lookup': {
from: 'Category',
localField: 'evaluations.idCategory',
foreignField: '_id',
as: 'category'
}
},
{
'$lookup': {
from: 'Club',
localField: 'idClub',
foreignField: '_id',
as: 'club'
}
},
{ '$unwind': { path: '$club', preserveNullAndEmptyArrays: true } },
{
'$lookup': {
from: 'Agent',
localField: 'idAgent',
foreignField: '_id',
as: 'agent'
}
},
{ '$unwind': { path: '$agent', preserveNullAndEmptyArrays: true } },
{
$match: {
$and: [
{ $exams: { $elemMatch: { deletedAt: { $exists: false } } } },
{ $sportPracticed: { deletedAt: { $exists: false } } },
{ $galery: { $elemMatch: { deletedAt: { $exists: false } } } },
{ $evaluationPlayer: { $elemMatch: { deletedAt: { $exists: false } } } },
{ $evaluations: { $elemMatch: { deletedAt: { $exists: false } } } },
{ $category: { $elemMatch: { deletedAt: { $exists: false } } } },
{ $club: { deletedAt: { $exists: false } } },
{ $agent: { deletedAt: { $exists: false } } },
]
}
}
]
However, when this code is executed, it returns the error: unknown top level operator: $ exams.
How can I solve this problem ?
My plans is not to bring data from relationships where it has already been deleted and what says that it was deleted is the existence of the deleteadAt;
Collection Player:
[{
"_id": "5f0cc0e676de351ce21a752b",
"language": "pt-br",
"country": "BR",
"status": true,
"name": "Laura Silva",
"nickname": "laurasilva",
"dateOfBirth": "1995-05-01T00:00:00.000Z",
"email": "laurasilva#gmail.com",
"phones": [],
"cpf": "54721452365",
"gender": "F",
"father": "Luiz Silva",
"mother": "Larissa Silva",
"weight": "67",
"height": "1.67",
"currentTeam": {
"name": "América",
"initialDate": "2020-01-01"
},
"professionalPlayer": true,
"bird": "ARW1",
"idSports": "5f0cbe10e6c0930b8dcc5181",
"competitions": [],
"exams": [],
"preference": [],
"coachReferrals": [],
"createdAt": "2020-07-13T20:15:34.348Z",
"updatedAt": "2020-07-13T20:15:34.348Z",
"__v": 0,
"idAgent": null,
"idClub": null
},
{
"_id": "5ee644c0280583764bfe7d97",
"currentTeam": {
"name": "Cruzeiro",
"initialDate": "2019-02-25"
},
"network": {
"instagram": {
"url": "#renanmoaesoficial"
}
},
"language": "pt-br",
"country": "BR",
"status": true,
"name": "Renan Moraes",
"nickname": "renanmoraes",
"dateOfBirth": "1993-01-21T00:00:00.000Z",
"email": "renan.desenvolviemnto#gmail.com",
"phones": [
{
"_id": "5ee644c0280583764bfe7d98",
"phone": "(31) 98796-1357"
}
],
"cpf": "123.367.952-85",
"gender": "M",
"father": "Antonio",
"mother": "Sandra",
"weight": "1,80",
"height": "45",
"professionalPlayer": false,
"bird": "2551566655",
"idSports": "5ee640d040b0a0649799c531",
"exams": [
{
"results": [],
"attestation": [],
"_id": "5ee644c0280583764bfe7d9a",
"idExams": "5ee6405f061a1362c3778435"
},
{
"results": [],
"attestation": [],
"_id": "5ee644c0280583764bfe7d99",
"idExams": "5ee6406e061a1362c3778436"
}
],
"standardPhoto": "https://exame.com/wp-content/uploads/2018/10/capaprofile.jpg?quality=70&strip=info",
"competitions": [],
"preference": [],
"coachReferrals": [],
"createdAt": "2020-06-14T15:39:44.198Z",
"updatedAt": "2020-06-14T15:39:44.198Z",
"__v": 0,
"idAgent": null,
"idClub": "5f176c8d58beb94efe56c59b"
}]
Collection medicalExams:
{
"_id": "5ee6406e061a1362c3778436",
"status": true,
"name": "Exames das prostatas",
"value": "1",
"type": "A",
"createdAt": "2020-06-14T15:21:18.114Z",
"updatedAt": "2020-06-14T15:21:18.114Z",
"__v": 0
},
{
"_id": "5ee6405f061a1362c3778435",
"status": true,
"name": "Exames dos rins",
"value": "3",
"type": "M",
"createdAt": "2020-06-14T15:21:03.405Z",
"updatedAt": "2020-06-14T15:21:03.405Z",
"__v": 0
}
Here on this site there is an example of the error, in which case the two items would need to come ... https://mongoplayground.net/p/IgnIt8wGvKq

Key references in $match stage shouldn't begin with $ sign.
Remove $ sign from the $match stage.
Also, the deletedAtkey for last two conditions should not be in separate parenthesis.
{
$match: {
$and: [
{ exams: { $elemMatch: { deletedAt: { $exists: false } } } },
{ galery: { $elemMatch: { deletedAt: { $exists: false } } } },
{ evaluationPlayer: { $elemMatch: { deletedAt: { $exists: false } } } },
{ evaluations: { $elemMatch: { deletedAt: { $exists: false } } } },
{ category: { $elemMatch: { deletedAt: { $exists: false } } } },
{ "sportPracticed.deletedAt": { $exists: false } },
{ "club.deletedAt": { $exists: false } },
{ "agent.deletedAt": { $exists: false } },
]
}
}

Well, I managed to solve my problem .. It turns out that I needed to make a pipeline for each existing lookup relationship, careful that I was looking for the data in the correct way.
I had relationships that were made in an array, and I needed to match each item in my array with an id from another collection. And to achieve this I added let to declare variables to be used within my lookup and then use $ in to do specific searches for those ids ..
Anyway the final object was like this, I took some items that were also not important to make it simpler.
{
"$lookup": {
"from": "Exams",
"let": {
"exams_items": "$exams.idExams"
},
"pipeline": [
{
"$match": {
"$expr": {
"$in": [
"$_id",
"$$exams_items"
]
},
"deletedAt": {
$exists: false
}
}
}
],
"as": "allExams"
}
},
{
"$lookup": {
"from": "Sports",
"let": {
"id_sport": "$idSports"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$_id",
"$$id_sport"
]
},
"deletedAt": {
$exists: false
}
}
}
],
"as": "sportPracticed"
}
},
{
$unwind: {
"path": "$sportPracticed",
"preserveNullAndEmptyArrays": true
}
},
{
"$lookup": {
"from": "Galery",
"let": {
"id_player": "$_id"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$idPlayer",
"$$id_player"
]
},
"deletedAt": {
$exists: false
}
}
}
],
"as": "galery"
}
},
{
"$lookup": {
"from": "EvaluationPlayer",
"let": {
"id_player": "$_id"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$idPlayer",
"$$id_player"
]
},
"deletedAt": {
$exists: false
}
}
}
],
"as": "evaluationPlayer"
}
},
{
$lookup: {
from: "Club",
localField: "idClub",
foreignField: "_id",
as: "club"
}
},
{
$unwind: {
"path": "$club",
"preserveNullAndEmptyArrays": true
}
},
{
$lookup: {
from: "Agent",
localField: "idAgent",
foreignField: "_id",
as: "agent"
}
},
{
$unwind: {
"path": "$agent",
"preserveNullAndEmptyArrays": true
}
}

Related

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

MongoDB join/lookup not working when using a pipeline

using a join in MongoDb I can get the values I want
(await this.ideasCollection).aggregate([
{
$match: { userId, deleted: { $ne: true } },
},
{
$lookup: {
from: 'teams',
localField: '_id',
foreignField: `ideas.daily.ideaId`,
as: 'teams',
},
},
])
but when I try to use a pipeline in order to get fewer fields(using $project) it doesn't work
(await this.ideasCollection).aggregate([
{
$match: { userId, deleted: { $ne: true } },
},
{
$lookup: {
from: 'teams',
let: { ideaId: '$_id' },
pipeline: [
{ $match: { $expr: { $eq: ['$ideas.daily.ideaId', '$$ideaId'] } } },
{ $project: { _id: 1, name: 1 } },
],
as: 'teams',
},
},
])
Is there some kind of trick to make the second option work?
Here's the structure of teams
{
"_id": { "$oid": "58948652ab5f580010faeb44" },
"name": "My team",
"ideas": {
"daily": [
{ "ideaId": { "$oid": "5b6d913e3e552800260904e1" }, "ordinal": 0 },
{ "ideaId": { "$oid": "5bbbc93459914f0013e3c522" }, "ordinal": 1 },
]
}
}
Thank you

How to check if an element exists in a document and return true or false depending on it?

I have an aggregation query in which I use $lookup to get data from other collections. But I cannot understand how do I get a boolean value if a $match is found.
Schema
const likesSchema = new mongoose.Schema({
user: {
id: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
},
storyID: {
type: String,
required: true,
}
}, {
timestamps: true
});
Complete Query
const user_id = req.authorizedUser.sub;
const stories = await Story.aggregate([
{
$lookup: {
from: "comments",
localField: "storyID",
foreignField: "storyID",
as: "comments"
},
},
{
$lookup: {
from: "likes",
let: {storyID: "$storyID"},
pipeline: [
{
$match: {
$expr: { $eq: ["$$storyID", "$storyID"] }
}
},
{
$facet: {
"total": [{ $count: "count" }],
"byMe": [{
$match: {
$expr: { $eq: ["$user.id", user_id] } // Need boolean value if found/ not found
}
}]
}
}
],
as: "likes"
}
},
Snippet of Response
"likes": [
{
"total": [
{
"count": 2
}
],
"byMe": [
{
"_id": "5d04fe8e982bb50bbcbd2b48",
"user": {
"id": "63p6PpPyOh",
"name": "Ayan Dey"
},
"storyID": "b0g5GA6ZJFKkJcnJlp6w8qGR",
"createdAt": "2019-06-15T14:19:58.531Z",
"updatedAt": "2019-06-15T14:19:58.531Z",
"__v": 0
}
]
}
]
Required Response
"likes": {
"total": 2,
"byMe": true
}
You can use below aggregation
{ "$lookup": {
"from": "likes",
"let": { "storyID": "$storyID" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$$storyID", "$storyID"] }}}
],
"as": "likes1"
}},
{ "$addFields": {
"likes.total": { "$size": "$likes1" },
"likes.byMe": { "$ne": [{ "$indexOfArray": ["$likes1.user.id", user_id] }, -1] }
}},
{ "$project": { "likes1": 0 }}
Or
{ "$lookup": {
"from": "likes",
"let": { "storyID": "$storyID" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$$storyID", "$storyID"] }}},
{ "$facet": {
"total": [{ "$count": "count" }],
"byMe": [{ "$match": { "$expr": { "$eq": ["$user.id", user_id] }}}]
}}
{ "$project": {
"total": {
"$ifNull": [{ "$arrayElemAt": ["$total.count", 0] }, 0 ]
},
"byMe": { "$ne": [{ "$size": "$byMe" }, 0] }
}}
],
"as": "likes"
}},
{ "$unwind": "$likes" }

Need field form $group in output after using match, lookup, unwind

I have applied following query to get the result but I am not getting total_members in the output:
PodMembers.aggregate([
{
$match: { datetime: { $exists: true } }
},
{
$group: {
_id: "$pod_id",
total_members: { $sum: 1 }
}
},
{ $unwind: "$total_members" },
{
$lookup: {
from: "pods",
localField: "_id",
foreignField: "_id",
as: "podinfo"
}
},
{ $unwind: "$podinfo" },
{ "$replaceRoot": { "newRoot": "$podinfo" } },
{ $addFields: { "Status": false } }
]).exec(function (err, resp) {
if (err) console.log(err)
else console.log(resp)
})
pods documents like:
{
"_id": "5ae46c0aff1bde1634ad8b3f",
"admin": "595bdd5aa6ea2811d48a7802",
"name": "Fashion Trend",
"datetime": 1524919038771,
"approval": false,
"actions": "Comments",
"description": "Fashion is about dressing according to what's fashionable. Style is more about being yourself.",
"profilepic": "https://cdn.com/upload/Community_photos/595bdd5a6ea2811d487802_152919188491.jpg",
"coverpic": "https://cdn.com/upload/Community_photos/595dd5aaea2811d48a7802_152499171374.jpg",
"__v": 0
}
pod_members documents like:
{
"_id": "5b127683187a4f19901e34b7",
"__v": 0,
"pod_id": "5ae470d04e15d607f043a20e",
"instaid": "5ad9a44cabd2180d64073462",
"username": "out_tur",
"user_id": "595bdd5aa6ea2811d48a7802",
"member_name": "Sagar Dalal",
"req_date": 1527936643123,
"datetime": 1527938142745,
}
I have also attached output which I am getting from above code: