Use in opperator after lookup and unwind - mongodb

I used mondo db version 5.0.5
And faced with strange behaviour
I have query with lookup and unwind and afetr that need apply $in operator and look like I have wrong behaviour, I faced with data which don't have fake_dta in device_tree_tbl.ancestors property, any idea why ?
db.getCollection('metric').aggregate(
{
$lookup: {
from: "device_tree",
localField: "pub_key_digest",
foreignField: "node_id",
as: "device_tree_tbl"
}
},
{
$unwind: {
'path': '$device_tree_tbl'
}
},
{
$match: {
'device_tree_tbl.ancestors': {$in: ['fake_dta']}
}
}
)

sorry about that, If someone faced with unexpected behaviour in aggregate query first of all need to check square brackets :)
works like needed
db.getCollection('metric').aggregate([
{
$match:
{ 'label': 'network', 'metric': 'rx_bytes' }
},
{
$lookup: {
from: "device_tree",
localField: "pub_key_digest",
foreignField: "node_id",
as: "device_tree_tbl"
}
},
{
$unwind: {
'path': '$device_tree_tbl'
}
},
{
$match: {
'device_tree_tbl.ancestors': {$in: ['1573394823429_4']}
}
},
{
$group: {
"_id": "$id"
}
},
{
$sort: { _id: 1 }
}
])

Related

MongoDB $lookup function replace whole document

I'm currently running a query that looks like this:
courses = await Enrollment.aggregate([
{
$match: {
userId: userId
}
},
{
$lookup: {
from: 'courses',
localField: 'course',
foreignField: '_id',
as: 'course'
}
},
{
$unwind: '$course'
},
{
$project: {
course: {
courseCode: true,
name: true,
officialCode: true,
}
}
}
]);
This produces results that look like this
[{
"_id": "61e0652ba5c2fe5bdcdbdc23",
"course": {
"courseCode": "code2",
"name": "Terst class 2",
"officialCode": "test 202"
}
}]
I'm wondering if there is a way for me to bring courseCode, name and officialCode to the "highest level" of the document?
Thank you in advance.
You can do it with $replaceRoot aggregation pipeline. Add this as the last step:
{
"$replaceRoot": {
"newRoot": "$course"
}
}
Working example

mongodb add field from another collection

I try to add field from another collection.
db.CarModifications.aggregate([
{
$lookup: {
from: "CarTypes",
localField: "CarTypeID",
foreignField: "CarTypeID",
as: "carType"
}
},
{
$addFields: {
CarType : "$carType._id"
}
},
{
$unwind: "$CarType"
},
{
$project: {
someField: 0
}
}
]).forEach(function(result) {
db.CarModifications.updateOne({_id: result._id}, {$set: {"CarType": result.CarType}})
})
Aggregation result show correct, but no documents update. What's wrong?

Mongoose lookup across 3 collections using foreign key

I have found a few questions that relate to this (here and here) but I have been unable to interpret the answers in a way that I can understand how to do what I need.
I have 3 collections: Organisations, Users, and Projects. Every project belongs to one user, and every user belongs to one organisation. From the user's id, I need to return all the projects that belong to the organisation that the logged-in user belongs to.
Returning the projects from the collection that belong to the user is easy, with this query:
const projects = await Project.find({ user: req.user.id }).sort({ createdAt: -1 })
Each user has an organisation id as a foreign key, and I think I need to do something with $lookup and perhaps $unwind mongo commands, but unlike with SQL queries I really struggle to understand what's going on so I can construct queries correctly.
EDIT: Using this query
const orgProjects = User.aggregate(
[
{
$match: { _id: req.user.id }
},
{
$project: { _id: 0, org_id: 1 }
},
{
$lookup: {
from: "users",
localField: "organisation",
foreignField: Organisation._id,
as: "users_of_org"
}
},
{
$lookup: {
from: "projects",
localField: "users_of_org._id",
foreignField: "user",
as: "projects"
}
},
{
$unset: ["organisation", "users_of_org"]
},
{
$unwind: "$projects"
},
{
$replaceWith: "$projects"
}
])
Seems to almost work, returning the following:
Aggregate {
_pipeline: [
{ '$match': [Object] },
{ '$project': [Object] },
{ '$lookup': [Object] },
{ '$lookup': [Object] },
{ '$unset': [Array] },
{ '$unwind': '$projects' },
{ '$replaceWith': '$projects' }
],
_model: Model { User },
options: {}
}
assuming your documents have a schema like this, you could do an aggregation pipeline like below with 2 $lookup stages.
db.users.aggregate(
[
{
$match: { _id: "user1" }
},
{
$project: { _id: 0, org_id: 1 }
},
{
$lookup: {
from: "users",
localField: "org_id",
foreignField: "org_id",
as: "users_of_org"
}
},
{
$lookup: {
from: "projects",
localField: "users_of_org._id",
foreignField: "user_id",
as: "projects"
}
},
{
$unset: ["org_id", "users_of_org"]
},
{
$unwind: "$projects"
},
{
$replaceWith: "$projects"
}
])

Mongo multiple $lookup in any collections

I'm trying to set up a query on the mongo that searches in 3 different collections.
Document of client:
{
"_id": ObjectId("1a")
"razaosocial:"32423424",
"prepository": [
{
"$ref": "prepository",
"$id": ObjectId("2a")
}
]
}
Document of prepository:
{
"_id": ObjectId("2a")
"name:"Jonh",
"prepository": {
"$ref": "representative",
"$id": ObjectId("3a")
}
}
Document of representative:
{
"_id": ObjectId("3a")
"name:"Josh"
}
I'm doing it this way, but it doesn't return anything:
db.clients.aggregate(
[
{
$lookup: {
from: 'prepository',
localField: 'prepository',
foreignField: 'id',
as: 'prepository'
}
},
{ $unwind: "$prepository" },
{ $lookup: {
from: 'representative',
localField: 'id',
foreignField: 'prepository._id',
as: 'prepository.repre'
}
},
{ $group: {
_id: "$_id",
client: { $first: "$razaosocial" },
users: {
$push: "$prepository"
}
} }
])
I'm trying to return
{
"_id": "1a"
"razaosocial:"32423424",
"prepository": [
{
"_id": "2a"
"name:"Jonh",
"representative": {
"_id": "3a"
"name:"Josh"
}
}
]
}
I am grateful for any help
You can use nested lookup,
$lookup with prepository collection
$match with prepository's id
$lookup with representative collection
$unwind deconstruct representative array
db.client.aggregate([
{
$lookup: {
from: "prepository",
as: "prepository",
let: { prepository: "$prepository" },
pipeline: [
{ $match: { $expr: { $in: ["$_id", "$$prepository"] } } },
{
$lookup: {
from: "representative",
localField: "representative",
foreignField: "_id",
as: "representative"
}
},
{ $unwind: "$representative" }
]
}
}
])
Playground

Meteor Mongo Aggregate $lookup specify output field

I have two collections: Products and Stocks.
The relation between these two collections is one to one.
Products structure:
{
_id:
sku:
....
}
Stocks structure :
{
_id:
sku:
availability: []
....
}
My query:
Products.aggregate([
{
$match: cAux
}, {
$lookup: {
from: "Stocks",
localField: "sku",
foreignField: "sku",
as: "availability"
}
}, {
$sort: PRODUCT_SORT
}
]);
The result from this "join" is
{
_id:
sku:
availability: {_id:, sku:, **availabity**: []}
...
}
The join is okay, but I would like to only have the availability array field being joined and not the whole Stock document. Whats the best way to accomplish this? Any help would be appreciated.
Solution
Products.aggregate([
{
$match: cAux
}, {
$lookup: {
from: "Stocks",
localField: "sku",
foreignField: "sku",
as: "availability"
}
}, {
$project: {
...PRODUCT_FIELDS,
availability: {
$arrayElemAt: ['$availability.availability', 0]
}
}
}, {
$sort: PRODUCT_SORT
}
]);