MongoDb documents join with inner objects - mongodb

I have 2 documents named calls and customers
i want to join locationId of calls to customers.location._id
calls
"_id": "5d456560221b9147e4af4b97",
"customerId": "5d0a3bbfac9470aea56ad619",
"locationId": "5d11d2c4cba8151f67f735b1",
"startDateTime": "2019-06-21T05:30:00.000Z",
"endDateTime": "2019-06-21T06:00:00.000Z"
}
customers
"_id": "5d0a3bbfac9470aea56ad619",
"locations": [
{
"_id": "5d11d2c4cba8151f67f735b1",
"phone": "9889599999",
"ext": "91",
"address": "sad",
"neighborhood": "sda",
"city": "punetest",
"state": "MH",
"zip": "589365",
"country": "india",
"isBillingAddress": false,
"taxPercentage": 0,
"type": "Residential",
"status": "Active",
"firstName": "A",
"lastName": "B"
},
{
"_id": "5d11e457cba8151f67f735b3",
"phone": "969696999",
"ext": "91",
"address": "",
"neighborhood": "",
"city": "udaipur",
"state": "raj",
"zip": "312563",
"country": "india",
"isBillingAddress": false,
"taxPercentage": 0,
"type": "Residential",
"status": "Deleted",
"firstName": "AB",
"lastName": "CD"
}
],
"createdAt": "2019-06-19T13:42:23.479Z",
"updatedAt": "2019-06-25T13:39:07.597Z"
}
[
{
$lookup: {
from: 'customers.locations',
localField: 'locationId',
foreignField: '_id',
as: 'customers.locations',
},
}
]);
it is not working
I have 2 documents named calls and customers i want to join locationId of calls to customers.location._id
I want output```
{
"_id": "5d456560221b9147e4af4b97",
"customerId": "5d0a3bbfac9470aea56ad619",
"locationId": "5d11d2c4cba8151f67f735b1",
"location":{"_id": "5d11d2c4cba8151f67f735b1",
"phone": "9889599999",
"ext": "91",
"address": "sad",
"neighborhood": "sda",
"city": "punetest",
"state": "MH",
"zip": "589365",
"country": "india",
"isBillingAddress": false,
"taxPercentage": 0,
"type": "Residential",
"status": "Active",
"firstName": "A",
"lastName": "B"}
}

Ok, this is what you're looking at :
If your locationId in calls has only one matching customer.locations._id in customer :
db.getCollection('calls').aggregate([
{
$lookup: {
from: 'customers',
localField: 'locationId',
foreignField: 'locations._id',
as: 'customersCalls',
}
}, { $unwind: '$customersCalls' },
{
$project: {
customerId: 1, locationId: 1, locations: {
$filter: {
input: "$customersCalls.locations",
as: "item",
cond: { $eq: ["$$item._id", '$locationId'] }
}
}
}
},
{ $group: { _id: '$_id', result: { $first: '$$ROOT' } } },
{ $replaceRoot: { newRoot: "$result" } }
])
else if your locationId in calls has multiple matching customer.locations._id in customer :
db.getCollection('calls').aggregate([
{
$lookup: {
from: 'customers',
localField: 'locationId',
foreignField: 'locations._id',
as: 'customersCalls',
}
}, { $unwind: '$customersCalls' },
{
$project: {
customerId: 1, locationId: 1, locations: {
$filter: {
input: "$customersCalls.locations",
as: "item",
cond: { $eq: ["$$item._id", '$locationId'] }
}
}
}
},
{ $group: { _id: '$_id', locations: { $push: { $arrayElemAt: ["$locations", 0] } }, result: { $first: '$$ROOT' } } },
{ $addFields: { 'result.locations': '$locations' } },
{ $replaceRoot: { newRoot: "$result" } }
])

Related

Display only select nested fields of object in MongoDB Compass aggregation

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

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
}
}
])

MongoDb: Find exact array match with duplicates

m trying to write a mongoDB query to find documents matching given example:
I have collection of users
{
"userId": "1",
"visitedPlaces": [
{
"city": "Kair",
"country": "Egypt"
},
{
"city": "Paris",
"country": "France"
},
{
"city": "Kair",
"country": "Egypt"
},
]
},
{
"userId": "2",
"visitedPlaces": [
{
"city": "Kair",
"country": "Egypt"
},
{
"city": "Paris",
"country": "France"
},
{
"city": "Paris",
"country": "France"
}
]
}
I want to write a query that will return me users which visited 'Kair' twice and 'Paris' once (user "2" is not matching this case)
I have tried query like
.find({"visitedPlaces.city": { "$all": ["Kair", "Paris", "Kair"] }, "visitedPlaces": { "$size": 3 } })
but it returns both users.
Is there a way to write such query in mongo ?
what about this one
db.getCollection('vists').aggregate([{
'$addFields': {
'countVisitedPlaces': {
'$map': {
'input': { '$setUnion': ['$visitedPlaces.city']},
'as': 'city',
'in': {
'city': '$$city',
'noOfTimeCityVists': {
'$size': {
'$filter': {
'input': '$visitedPlaces',
'as': 'visitedCity',
'cond': { '$eq': ['$$visitedCity.city', '$$city'] }
}
}
}
}
}
}
},
// here you got city wise visits count
{
$match: {
$and: [{
'countVisitedPlaces': {
'$elemMatch': {'noOfTimeCityVists': 2, 'city': 'Kair'}
}},
{
'countVisitedPlaces': {
'$elemMatch': {'noOfTimeCityVists': 1, 'city': 'Paris'}
}}
]}
}])
You change last stag of pipeline for different differnt search and your result.
Check the below query. You just need to modify $match depending on your condition.
db.collection.aggregate({
"$unwind": "$visitedPlaces"
},
{
"$group": {
"_id": {
"userId": "$userId",
"city": "$visitedPlaces.city"
},
"count": {
"$sum": 1
}
}
},
{
"$project": {
"userId": "$_id.userId",
"cityCount": {
"city": "$_id.city",
"count": "$count"
},
"_id": 0
}
},
{
"$group": {
"_id": "$userId",
"cityCount": {
"$push": "$cityCount"
}
}
},
{
"$match": {
"cityCount": {
"$all": [
{
"$elemMatch": {
"city": "Kair",
"count": 2
}
},
{
"$elemMatch": {
"city": "Paris",
"count": 1
}
}
]
}
}
},
{
"$project": {
"userId": "$_id",
"_id": 0
}
})
Here is MongoPlayground for you.

Mongo lookup to join a child/sub object?

I am joining booking and customers collections.
My bookings object looks like this:
{
"bookingID": 1,
"customerID": "adam.apple#email.com",
"room": [
{
"roomID": "JDS",
"numRooms": 1
}
]
}
and customer object like this:
{
"customer": {
"firstname": "Adam",
"surname": "Apple",
"title": "Nr.",
"emailAddress": "adam.apple#email.com"
},
"address": {
"street": "221B Baker St",
"city": "London",
"state": null,
"zipcode": "NW1 6XE",
"country": "UK"
}
}
I am using this code:
{ $lookup: {from: 'customers', localField: 'customerID', foreignField: 'customer.emailAddress', as: 'traveller'} },
{ $unwind: '$traveller' },
{ $project: {'traveller': {_id: 0, 'address': 0}} }
to combine the output. I'd like to get:
"traveller": {
"firstname": "Adam",
"surname": "Apple",
"title": "Nr.",
"emailAddress": "adam.apple#email.com"
}
and I get:
"traveller": {
"customer": {
"firstname": "Adam",
"surname": "Apple",
"title": "Nr.",
"emailAddress": "adam.apple#email.com"
}
}
How do I do this?
You can check it here:
https://mongoplayground.net/p/ik2UtP4-EHa
Here you go :-
Just change the project stage as below -
{
$project: {
"traveller": "$traveller.customer",
"bookingID": 1,
"cruise": 1,
"customerID": 1,
"room": 1
}
}
Mongo Playground
Try this one its not break your other pipelines
aggregate([{
$lookup: {
from: 'customers',
localField: 'customerID',
foreignField: 'customer.emailAddress',
as: 'traveller'
} },
{ $unwind: '$traveller' },
{ $project: {
'traveller':"$traveller.customer",
bookingID:1,
cruise:1,
customerID:1,
room:1,
} }])

How to Pull Out nested Objects in Mongodb?

I'm trying to make a query by merging from another collection, but there are obstacles when the query is run, the data generated is not what I imagined
i have the data like this
{
"_id": "5ce8981a46039c14a4ec32d1",
"name": "Monkey D Luffy",
"email": "aaa#aaa.com",
"status": "not verified",
"password": "$2a$10$ayluBIsOOelBTIk.69GjHubgQemr6dJfgBUELNusCOaUGLpS/qKs6",
"metas": {
"role": "admin",
"smartphone": "ios",
"address": "konoha",
"hobby": "eat ramen"
}
},
and i want pull out metas from nested document :
{
"_id": "5ce8981a46039c14a4ec32d1",
"name": "Monkey D Luffy",
"email": "aaa#aaa.com",
"status": "not verified",
"password": "$2a$10$ayluBIsOOelBTIk.69GjHubgQemr6dJfgBUELNusCOaUGLpS/qKs6",
"role": "admin",
"smartphone": "ios",
"address": "konoha",
"hobby": "eat ramen"
},
if any duplicate from my question pls suggest me, because I didn't find the same question, mostly using arrays.
and here is my query:
db.accounts.aggregate([
{
$lookup: {
from: "account_meta",
localField: "_id",
foreignField: "account_id",
as: "metas"
}
},
{ "$unwind": "$metas" },
{
$group: {
_id: "$_id",
name: {$first:"$name"},
status: {$first: "$status"},
email: {$first: "$email"},
password: {$first: "$password"},
data: {
"$push": {
"k" : "$metas.key",
"v": "$metas.value"
}
}
}
},
{
$project: {
"_id": "$_id",
"name": "$name",
"email": "$email",
"status": "$status",
"password": "$password",
"metas" :{
$arrayToObject: "$data"
}
}
},
{
"$replaceRoot": {
"newRoot":
{
"$mergeObjects": [ {$arrayToObject: "$data"}, "$$ROOT"]
},
}
},
])
i just edit some code from my $mergeObject:
{
"$replaceRoot": {
"newRoot":
{
"$mergeObjects": [ "$metas", "$$ROOT"]
},
}
},
{$project: { metas: 0} }