Nested lookup in mongo db query - mongodb

I am making a airline dummy webside, and i need get all sold tickets per flight for all airlines, i have 3 collections: airlines, flights and sales
I tried using a nested lookups in mongodb query, but i cant sum the total tickets, here is the current query and the result:
Airline.aggregate([{
$lookup: {
from: "flights",
localField: "id_airline",
foreignField: "id_airline",
as: "flights"
}
}, {
$unwind: {
path: "$flights",
preserveNullAndEmptyArrays: true
}
}, {
$lookup: {
from: "sales",
localField: "flights.id_flight",
foreignField: "id_flight",
as: "flights.sales",
}
}, {
$group: {
_id : "$_id",
idAirline: { $first: "$id_airline" },
flights: { $push: "$flights" }
}
}, {
$project: {
_id: 1,
idAirline: 1,
"flights.id_flight": 1,
"flights.price": 1,
"flights.sold":{$sum:"$flights.sales.tickets"}
}
}]
And the result is:
... },
{
"_id": "5db381cb18518043c40e3ecd",
"idAirline": "AVI-242",
"flights": [
{
"id_flight": "CPA-001",
"price": "125",
"sold": 0
},
{
"id_flight": "CGA-002",
"price": "150",
"sold": 0
},
{
"id_flight": "CHA-003",
"price": "135",
"sold": 0
}
]
},
....
Actually the fligth CPA-001 has 6 tickets sold but i cant sum a get the result.
Here are the documents:
Airlines
{"_id":{"$oid":"5db3823718518043c40e3ece"},"country":["Panamá","El Salvador","Belice"],"id_airline":"VOL-643","name_airport":"Juan Santamaría","name_airline":"Volaris","createdAt":{"$date":{"$numberLong":"1572045367094"}},"updatedAt":{"$date":{"$numberLong":"1572045367094"}},"__v":{"$numberInt":"0"}}
Flights
{"_id":{"$oid":"5db9a225154a1b1b08cc77c3"},"restrictions":["No Liquids"],"features":[],"id_flight":"CPA-001","id_airline":"AVI-242","date_departure":{"$date":{"$numberLong":"1546300800000"}},"date_arrival":{"$date":{"$numberLong":"1559779200000"}},"name":"CosPan","origin":"Costa Rica","destination":"Panamá","itinerary":"50 breakfasts","price":"125","status":"On Time","max_capacity":"50","createdAt":{"$date":{"$numberLong":"1572446757327"}},"updatedAt":{"$date":{"$numberLong":"1572447464367"}},"__v":{"$numberInt":"0"}}
Sales
{"_id":{"$oid":"5db9b643b50c0d1540b8db89"},"id_user":"304780391","id_flight":"CPA-001","origin":"Costa Rica","destination":"Panamá","date_departure":{"$date":{"$numberLong":"1546300800000"}},"date_arrival":{"$date":{"$numberLong":"1559779200000"}},"tickets":{"$numberInt":"4"},"suitcases":{"$numberInt":"1"},"status":"Bought","seat":{"$numberInt":"-1"},"createdAt":{"$date":{"$numberLong":"1572451907375"}},"updatedAt":{"$date":{"$numberLong":"1572451907375"}},"__v":{"$numberInt":"0"}}

I think the nested arrays are causing some difficulties. I added another $unwind between $lookup and $group. Let me know what you think...
db.airlines.aggregate([
{ $lookup: {
from: "flights",
localField: "id_airline",
foreignField: "id_airline",
as: "flights"
}
},
{ $unwind: {
path: "$flights",
preserveNullAndEmptyArrays: true
}
},
{ $lookup: {
from: "sales",
localField: "flights.id_flight",
foreignField: "id_flight",
as: "flights.sales",
}
},
{ $unwind: {
path: "$flights.sales",
preserveNullAndEmptyArrays: true
}
},
{ $group: {
_id : "$_id",
idAirline: { $first: "$id_airline" },
flights: { $push: "$flights" }
}
},
{ $project: {
_id: 1,
idAirline: 1,
"flights.id_flight": 1,
"flights.price": 1,
"flights.sold":{$sum: "$flights.sales.tickets"}
}
}
]).pretty()
Documents used to test:
flights
{
"_id" : ObjectId("5db9a225154a1b1b08cc77c3"),
"restrictions" : [
"No Liquids"
],
"features" : [ ],
"id_flight" : "CPA-001",
"id_airline" : "VOL-643",
"date_departure" : ISODate("2019-10-30T23:04:17.119Z"),
"date_arrival" : ISODate("2019-10-30T23:04:17.119Z"),
"name" : "CosPan",
"origin" : "Costa Rica",
"destination" : "Panamá",
"itinerary" : "50 breakfasts",
"price" : "125",
"status" : "On Time",
"max_capacity" : "50",
"createdAt" : ISODate("2019-10-30T23:04:17.119Z"),
"updatedAt" : ISODate("2019-10-30T23:04:17.119Z"),
"__v" : {
"$numberInt" : "0"
}
}
airlines
{
"_id" : ObjectId("5db3823718518043c40e3ece"),
"country" : [
"Panamá",
"El Salvador",
"Belice"
],
"id_airline" : "VOL-643",
"name_airport" : "Juan Santamaría",
"name_airline" : "Volaris",
"createdAt" : ISODate("2019-10-30T23:04:17.119Z"),
"updatedAt" : ISODate("2019-10-30T23:04:17.119Z"),
"__v" : {
"$numberInt" : "0"
}
}
sales
[{
"_id" : ObjectId("5db9b643b50c0d1540b8db89"),
"id_user" : "304780391",
"id_flight" : "CPA-001",
"origin" : "Costa Rica",
"destination" : "Panamá",
"date_departure" : ISODate("2019-10-30T23:04:17.119Z"),
"date_arrival" : ISODate("2019-10-30T23:04:17.119Z"),
"tickets" : 4,
"suitcases" : {
"$numberInt" : "1"
},
"status" : "Bought",
"seat" : -1,
"createdAt" : ISODate("2019-10-30T23:04:17.119Z"),
"updatedAt" : ISODate("2019-10-30T23:04:17.119Z"),
"__v" : {
"$numberInt" : "0"
}
},
{
"_id" : ObjectId("5db9b643b50c0d1540b8db8a"),
"id_user" : "304780391",
"id_flight" : "CPA-001",
"origin" : "Costa Rica",
"destination" : "Panamá",
"date_departure" : ISODate("2019-10-30T23:04:17.119Z"),
"date_arrival" : ISODate("2019-10-30T23:04:17.119Z"),
"tickets" : 4,
"suitcases" : {
"$numberInt" : "1"
},
"status" : "Bought",
"seat" : -1,
"createdAt" : ISODate("2019-10-30T23:04:17.119Z"),
"updatedAt" : ISODate("2019-10-30T23:04:17.119Z"),
"__v" : {
"$numberInt" : "0"
}
}]

Related

Mongodb Aggregation get Data per user

Report table sample data
{
"_id" : ObjectId("614415f4a6566a001623b622"),
"record" : [
{
"dateTime" : ISODate("2021-09-17T04:13:39.465Z"),
"status" : "time-in",
"month" : 9,
"day" : 17,
"year" : 2021,
"time" : 1631852019465.0,
"date" : ISODate("2021-09-17T00:00:00.000Z"),
},
{
"dateTime" : ISODate("2021-09-17T04:14:01.182Z"),
"status" : "time-out",
"month" : 9,
"day" : 17,
"year" : 2021,
"time" : 1631852041182.0,
"date" : ISODate("2021-09-17T00:00:00.000Z"),
}
],
"uid" : ObjectId("614415b0a6566a001623b80b"),
"date" : ISODate("2021-09-17T00:00:00.000Z"),
"status" : "time-out",
"createdAt" : ISODate("2021-09-17T04:13:40.102Z"),
"updatedAt" : ISODate("2021-09-17T04:14:01.831Z"),
"__v" : 0
}
Users table sample data
{
"_id" : ObjectId("615c0f6db30aff375cd05ac1"),
"displayName" : "test test",
"firstName" : "test",
"lastName" : "test",
"email" : "test#gmail.com",
"brand" : "Jollibee",
"phone" : "+632312312312312",
"role" : 1,
"isVerified" : true,
"isArchived" : false,
"createdAt" : ISODate("2021-10-05T08:40:13.208Z"),
"updatedAt" : ISODate("2021-10-05T08:40:13.208Z"),
"__v" : 0
}
I have a data like this
db.getCollection('users').aggregate([
{
"$match": { brand: "Jollibee" }
},
{
$lookup: {
from: "orders",
let: { id: 'id' },
pipeline: [
{
$match: {
date: { $gte: ISODate("2020-11-01"), $lt: ISODate("2021-11-31") },
}
}
],
as: "orders",
},
},
{
$project: {
"_id": 1,
"name": 1,
"orders": 1
}
}
])
when I'm using this aggregation I'm getting all the data inserted per user.
What I want to happen is that. I will only get the data that belong to the user and not all the data of all users.
Added the sample documents for each collection
You are not comparing the userIds of both collections. You should add that on your $match. Playground
db.users.aggregate([
{
"$match": {
brand: "Jollibee"
}
},
{
$lookup: {
from: "orders",
let: {
id: "$_id"
},
pipeline: [
{
$match: {
date: {
$gte: ISODate("2020-11-01"),
$lt: ISODate("2021-11-30")
},
$expr: {
$eq: [
"$uid",
"$$id"
]
}
}
}
],
as: "orders",
},
},
{
$project: {
"_id": 1,
"name": 1,
"orders": 1
}
}
])

Several $lookup in a single MongoDB query

I am currently creating a request, but I can not.
So there is one the document of 1 user:
"_id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"search" : "flarize",
"name" : "flarize",
"email" : "flarize.a473#gmail.com",
"password" : "$2a$10$eYeOtEkEUyD7TFkjKvhZOuSSpvBolkL17TrPHuoHhOT8JrsQR0UKW",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 1540501286109,
"friend" : [
{
"id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"date" : 1540713424488
}
]
And my query:
db.users.aggregate([{
$match:{
search: "flarize"
}},{
$lookup:{
from: "users",
let:{friendId:"$friend.id"},
pipeline:[{
$match:{
$expr:{
$in:["$_id","$$friendId"]
}
}},{
$limit:10},{
$skip:0},{
$project: {
name: 1,
search:1,
desc:1,
friend:1,
date:1,
banner:1,
profil:1,
color: 1
}
}],
as:"friends"}},{
$project:{
profil:1,
search:1,
name:1,
profile:1,
banner:1,
color:1,
date:1,
desc:1,
friend:1,
friends:1
}
}]).pretty();
I got this result:
{
"_id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"search" : "flarize",
"name" : "flarize",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 1540501286109,
"friend" : [
{
"id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"date" : 1540713424488
}
],
"friends" : [
{
"_id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"search" : "flarize",
"name" : "flarize",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 1540501286109,
"friend" : [
{
"id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"date" : 1540713424488
}
]
}
]
}
It's not really what I want.I would like Compare the document of the selection person, and the one who requests the query if the id of the person selected is present in friend then is_friend will be equal to true otherwise it will be equal to false.
I try this think:
db.users.aggregate([{
$match:{
search: "flarize"
}},{
$lookup:{
from: "users",
let:{friendId:"$friend.id"},
pipeline:[{
$match:{
$expr:{
$in:["$_id","$$friendId"]
}
}},{
$limit:10},{
$skip:0},{
$project: {
name: 1,
search:1,
desc:1,
friend:1,
date:1,
banner:1,
profil:1,
color: 1
is_friend:{
$lookup:{
from:"users",
let:{friendIdIs:"$_id"},
pipeline:[{
$match:{
$expr:{
$and:[{
$in:["$$friendIdIs", "$friend.is"]},{
$eq:["_id", ObjectId("5bd22f28f77cfb1f6ce503ca")]
}]
}
}
}],
as:"yes"}}
}
}
}],
as:"friends"}},{
$project:{
profil:1,
search:1,
name:1,
profile:1,
banner:1,
color:1,
date:1,
desc:1,
friend:1,
friends:1
}
}]).pretty();
But it's don't work.
Thank you for helping me

Mongodb $lookup joins all collection instead of matching object

so I am trying to do a $lookup with Mongodb but I have a strange output.
I have two collections, "sites" and "consumptions".
sites :
{
"_id" : ObjectId("5b26db6e7f59e825909da106"),
"siteId" : 49,
"industry" : "Commercial Property",
"sub_industry" : "Shopping Center/Shopping Mall",
"square_feet" : 497092,
"latitude" : 41.2161756,
"longitude" : -78.14809154,
"timezone" : "America/New_York",
"timezone_offset" : "-04:00",
"__v" : 0
}
consumptions :
{
"_id" : ObjectId("5b26db907f59e825909f3d2a"),
"timestamp" : 1325382000,
"dttm_utc" : ISODate("2012-01-01T00:40:00Z"),
"value" : 2.8956,
"estimated" : 0,
"anomaly" : "",
"site" : [
{
"_id" : ObjectId("5b26db727f59e825909da16a")
}
],
"__v" : 0
}
This is the $lookup I am trying to do :
db.consumptions.aggregate([
{
$lookup:
{
from: "sites",
localField: "site.id",
foreignField: "id",
as: "site"
}
}
])
The expected output would be to have the detail of the site in each consumption :
{
"_id" : ObjectId("5b26db907f59e825909f3d2a"),
"timestamp" : 1325382000,
"dttm_utc" : ISODate("2012-01-01T00:40:00Z"),
"value" : 2.8956,
"estimated" : 0,
"anomaly" : "",
"site" : [
{
"_id" : ObjectId("5b26db6e7f59e825909da106"),
"siteId" : 49,
"industry" : "Commercial Property",
"sub_industry" : "Shopping Center/Shopping Mall",
"square_feet" : 497092,
"latitude" : 41.2161756,
"longitude" : -78.14809154,
"timezone" : "America/New_York",
"timezone_offset" : "-04:00",
"__v" : 0
}
],
"__v" : 0
}
This is the output I am getting with the $lookup :
{
"_id" : ObjectId("5b26db907f59e825909f3d2a"),
"timestamp" : 1325382000,
"dttm_utc" : ISODate("2012-01-01T00:40:00Z"),
"value" : 2.8956,
"estimated" : 0,
"anomaly" : "",
"site" : [
{
"_id" : ObjectId("5b26db6e7f59e825909da0f3"),
"siteId" : 6,
"industry" : "Commercial Property",
"sub_industry" : "Shopping Center/Shopping Mall",
"square_feet" : 161532,
"latitude" : 34.78300117,
"longitude" : -106.8952497,
"timezone" : "America/Denver",
"timezone_offset" : "-06:00",
"__v" : 0
},
{
"_id" : ObjectId("5b26db6e7f59e825909da0f4"),
"siteId" : 8,
"industry" : "Commercial Property",
"sub_industry" : "Shopping Center/Shopping Mall",
"square_feet" : 823966,
"latitude" : 40.32024733,
"longitude" : -76.40494239,
"timezone" : "America/New_York",
"timezone_offset" : "-04:00",
"__v" : 0
}, ... (all the sites details are listed)
],
"__v" : 0
}
Thank you in advance for your help !
You need to first $unwind the site array to match site._id to the foreign field _id and then $group to rolling back into the arrays again.
db.collection.aggregate([
{ "$unwind": "$site" },
{ "$lookup": {
"from": Site.collection.name,
"localField": "site._id",
"foreignField": "_id",
"as": "site"
}},
{ "$unwind": "$site" },
{ "$group": {
"_id": "$_id",
"value": { "$first": "$value" },
"estimated": { "$first": "$estimated" },
"anomaly": { "$first": "$anomaly" },
"timestamp": { "$first": "$timestamp" },
"dttm_utc": { "$first": "$dttm_utc" },
"site": { "$push": "$site" }
}}
])
And if you have mongodb 3.6 then you can try this
db.collection.aggregate([
{ "$unwind": "$site" },
{ "$lookup": {
"from": Site.collection.name,
"let": { "siteId": "$site._id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$siteId" ] } } }
],
"as": "site"
}},
{ "$unwind": "$site" },
{ "$group": {
"_id": "$_id",
"value": { "$first": "$value" },
"estimated": { "$first": "$estimated" },
"anomaly": { "$first": "$anomaly" },
"timestamp": { "$first": "$timestamp" },
"dttm_utc": { "$first": "$dttm_utc" },
"site": { "$push": "$site" }
}}
])
Make sure you should put Site.collection.name correctly
I think that The $lookup doesn't work directly with an array.
try using $unwind first.

Aggregate by array field with object ids

Is there a better way of retrieving values from a collection2 based on an array field with object ids in collection1? I've tried to use $project but failed to get all required fields
Collections to aggregate:
collection1:
{
"_id" : ObjectId("5a58910de202796cfef41c6a"),
"sortOrder" : 5,
"title" : "Question 1 ?",
"freeTextIncluded" : false,
"freeText" : false,
"resultChart" : "pieChart",
"answer" : [
ObjectId("5a579fefd5554706b446cc71"),
ObjectId("5a587f17e4b2de0d683f96a4"),
ObjectId("5a587f20e4b2de0d683f96a5"),
ObjectId("5a587f29e4b2de0d683f96a6")
],
"state" : "active",
"__v" : 1,
"description" : ""
}
collection2:
{
"_id" : ObjectId("5a579fefd5554706b446cc71"),
"slug" : "answer-1",
"title" : "Answer 1",
"state" : "active",
"__v" : 0,
"author" : ObjectId("5a2e6b56e593c8525ced34b8"),
"body" : "<p>Lipsum...</p>"
}
{
"_id" : ObjectId("5a587f17e4b2de0d683f96a4"),
"slug" : "answer-2",
"title" : "Answer 2",
"state" : "active",
"__v" : 0,
"body" : ""
}
{
"_id" : ObjectId("5a587f20e4b2de0d683f96a5"),
"slug" : "answer-3",
"title" : "Answer 3",
"state" : "active",
"__v" : 0,
"body" : "",
"isCorrect" : true,
"sortOrder" : 3
}
{
"_id" : ObjectId("5a587f29e4b2de0d683f96a6"),
"slug" : "answer-4",
"title" : "Answer 4",
"state" : "active",
"__v" : 0,
"body" : ""
}
This aggregation works ok but I'm just wondering if there's a better/shorter way of aggregating 2 collections...
db.getCollection('questions').aggregate([
{
$match: {'_id': ObjectId('5a58910de202796cfef41c6a') }
},
{
$unwind: "$answer"
},
{
$lookup:
{
from: "answers",
localField: "answer",
foreignField: "_id",
as: "answers"
}
},
{
$match: { "answers": { $ne: [] }}
},
{
$unwind: "$answers"
},
{
$group: {
_id : ObjectId('5a58910de202796cfef41c6a'),
answerList: {$push: "$answers"},
title: {$first: "$title"},
sortOrder: {$first: "$sortOrder"},
description: {$first: "$description"},
resultChart: {$first: "$resultChart"},
freeTextIncluded: {$first: "$freeTextIncluded"},
}
}
]);
You need to improve your query like this:
db.getCollection('test').aggregate([{
$match: {
'_id': ObjectId('5a58910de202796cfef41c6a')
}
},
{
$lookup: {
from: "answers",
localField: "answer",
foreignField: "_id",
as: "answers"
}
},
{
$unwind: {
path: "$answers",
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: ObjectId('5a58910de202796cfef41c6a'),
answerList: {
$push: "$answers"
},
title: {
$first: "$title"
},
sortOrder: {
$first: "$sortOrder"
},
description: {
$first: "$description"
},
resultChart: {
$first: "$resultChart"
},
freeTextIncluded: {
$first: "$freeTextIncluded"
},
}
}])

Aggregate result group objects

Where I arrived was this I needed to put the user data on the athele:
{
"_id" : ObjectId("5963c6aa1aaf2c1c702ea86f"),
"updatedAt" : ISODate("2017-07-10T18:25:46.941+0000"),
"createdAt" : ISODate("2017-07-10T18:25:46.933+0000"),
"name" : "athleta01",
"nickname" : "01",
"email" : "aaaa#terra.com.br",
"birthday" : ISODate("1986-09-15T03:00:00.000+0000"),
"gender" : "0",
"disable" : false,
"deletedAt" : false,
"profile" : [
{
"departament" : ObjectId("5963c6281aaf2c1c702ea86c"),
"profession" : "athlete",
"_id" : ObjectId("5963c6aa1aaf2c1c702ea870")
}
],
"photo" : null,
"__v" : NumberInt(0)
}
doc Athlete:
{
"_id" : ObjectId("5963c6aa1aaf2c1c702ea871"),
"updatedAt" : ISODate("2017-07-10T19:53:08.285+0000"),
"createdAt" : ISODate("2017-07-10T18:25:46.948+0000"),
"position" : "atacante",
"shirt" : NumberInt(15),
"document" : "87956421345",
"weight" : "10.5",
"height" : "2.73",
"profileId" : ObjectId("5963c6aa1aaf2c1c702ea870"),
"disable" : false,
"deletedAt" : false,
"device" : {
"activityLevel" : "vai atuazliar",
"maxHeartRate" : NumberInt(45),
"reposeHeartRate" : NumberInt(90),
"codSensor" : "1a2s4e1s"
},
"__v" : NumberInt(0)
}
Already tried to make the exit with the project and to set up a group also I did not have the result that I expected. I think I'm missing out on some point.
db.users.aggregate(
[
{
$match: {
"profile.departament" : ObjectId("5963c6281aaf2c1c702ea86c")
}
},
{
$lookup: {
"from" : "institution",
"localField" : "profile.departament",
"foreignField" : "departament._id",
"as" : "user_departament"
}
},
{
$lookup: {
"from" : "athlete",
"localField" : "profile._id",
"foreignField" : "profileId",
"as" : "athlete_departament"
}
},
{
$unwind: {
path: "$athlete_departament",
preserveNullAndEmptyArrays: true
}
},
{
$lookup: {
from: "users",
localField: "athlete_departament.profileId",
foreignField: "profile._id",
as: "username",
}
},
{
$group: {
_id: { name: "$user_departament.name", cnpj: "$user_departament.cnpj", photo: "$user_departament.photo"},
departaments: {
$push : "$user_departament.departament"
},
athletes: {
$push : '$athlete_departament',
}
}
},
{$unwind : "$departaments"},
{$unwind : "$departaments"},
{$unwind : "$_id.name"},
{$unwind : "$_id.cnpj"},
{$unwind : "$_id.photo"},
{$unwind : "$athletes"},
{$unwind : "$athletes"},
{
$group : {
_id : "$_id",
departaments : {$addToSet : "$departaments"},
athletes : {$addToSet : "$athletes"}
}
},
{ "$project": {
//_id : { name: "$_id", departaments: { $concatArrays: [ {$arrayElemAt: [ "$departaments", 0 ]}, "$profiles", "$athletes" ] }}
_id : { institution: "$_id", departaments: { info: "$departaments", profiles: "$profiles", athletes: { username: "$username", athlete: "$athletes" }, }}
//_id : { name: "$_id", departaments: { "departament": { $concatArrays: [ { $arrayElemAt: ["$departaments", 0]}, "$athletes" ] }}}
//_id : { name: "$_id", departaments: { $concatArrays: [ {$arrayElemAt: [ "$departaments", 0 ]}, "$profiles", "$athletes" ] }}
}},
{$unwind : "$_id.departaments.info"},
{$unwind : "$_id.departaments.info"}
]);