mongodb add field from another collection - mongodb

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?

Related

Aggregate between referenced collections in MongoDB

Couldn't find an answer here
I got a collection of segments, where an example segment looks like this:
{
_id: {
$oid: "62e5778e34362ad54db6b3f9"
},
name: "Good-Natured Developers"
}
And a collection of users, where an example user looks like this:
{
_id: {
$oid: "62e5225dfdc41ba4f7effefa"
},
age: {
$numberInt: "43"
},
segment_ids: [
{
$oid: "62e577a034362ad54db6b40a"
},
{
$oid: "62e5782f34362ad54db6b497"
},
]
}
How can I query how many users are there in every segment?
I tried this aggregation:
const usersInSegment = await userCollection
.aggregate([
{ $unwind: '$users'},
{ $project: { "_id": 1} },
{
$lookup: {
from: 'segments',
localField: 'segment_ids',
foreignField: '_id',
as: 'joined'
}
}
])
.limit(25)
.toArray()
But I get an empty array.

Use in opperator after lookup and unwind

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

mongoDB, mongoose - aggregation an array of objects

I have 3 collections to aggregate.
1st is colors collection
{
{
_id: 1, <- mongoose objectId
name: red
},
{
_id: 2, <- mongoose objectId
name: green
}
}
2nd is products
{
{
_id: Id777, <- mongoose objectId
productName: test prod 777
},
{
_id: Id888, <- mongoose objectId
productName: test prod 888
}
}
and 3rd it move collection
{
....other fields here
items: [
{
_id: an mongoose id,
itemId: Id777 <- in products collection,
itemColor: 1 <- id in colors collection,
coutn: 7,
....other fields
},
{
_id: an mongoose id,
itemId: Id888 <- in products collection,
itemColor: 2 <- id in colors collection
cout: 10
....other fields
}
]
}
I need to have an output like this:
{
////information from collection
items: [
{
itemId: test prod 777, itemColor: red, count: 7
},
{
itemId: test prod 888, itemColor: green, count: 10
}
]
}
My code is:
const moves = await ProductMoves.aggregate([
{ $match: query }, // this is my query
{
$lookup: {
from: 'products',
localField: 'items.itemId',
foreignField: '_id',
as: 'productName'
}
},
{
$unwind: { path: "$productName" , preserveNullAndEmptyArrays: true }
},
{
$lookup: {
from: 'colors',
localField: 'items.itemColor',
foreignField: '_id',
as: 'cName'
}
},
{
$unwind: { path: "$cName" , preserveNullAndEmptyArrays: true }
},
{
$addFields: {
mItems: {
prName: "$productName.productName",
prColor: "$cName.colorName"
},
productName: 0,
cName: 0
}
}
])
.sort({addedDate: -1})
.skip(+req.query.offset)
.limit(+req.query.limit)
but it returns only 1 element from the object array. probably I need something like a for loop, but i couldn't do it.
thank you for your responses, and have a good day!
$unwind deconstruct items array
$lookup with products collection
$lookup with colors collection
$addFields, $arrayElemAt to get first element from lookup result
$group by _id and reconstruct items array and pass other fields as well
there is no external methods in an aggregate function, you have to use stages for sort, skip and limit like below
$sort by addedDate in descending order
$skip and $limit result
const moves = await ProductMoves.aggregate([
{ $match: query }, // this is my query
{ $unwind: "$items" },
{
$lookup: {
from: "products",
localField: "items.itemId",
foreignField: "_id",
as: "itemId"
}
},
{
$lookup: {
from: "colors",
localField: "items.itemColor",
foreignField: "_id",
as: "itemColor"
}
},
{
$addFields: {
"items.itemId": { $arrayElemAt: ["$itemId.productName", 0] },
"items.itemColor": { $arrayElemAt: ["$itemColor.name", 0] }
}
},
{
$group: {
_id: "$_id",
items: { $push: "$items" },
addedDate: { $first: "$addedDate" }
// add other fields that you want in result like "addedDate"
}
},
{ $sort: { addedDate: -1 } },
{ $skip: +req.query.offset },
{ $limit: +req.query.limit }
])
Playground

search on multiple collections with mongodb

I want to check if particular data is present on multiple documents or not.
eg I want to check if email exists in user collection and customer collection if it does then want to fetch the data.
I have tried below query but it fails as it checks only one collection.
db.t_usermasters.aggregate([
{
$match: {
"email" : "test#test.com"
}
},{
$lookup: {
from: "t_customermasters",
localField: "email",
foreignField: "email",
as: "UserDetails"
}
}
]).pretty();
if(db.t_usermasters.count({email: 'test#test.com'})
&& db.t_customermasters.count({email: 'test#test.com'})) {
/* fetch your data here
you can associate these two collections by using a customerId field in your
usermasters collection and then populate it ('customerId')
while fetching the data from usermasters collection */
}
Try this code:
db.t_usermasters.aggregate([
{
$match: {
"email" : "test#test.com"
}
},{
$lookup: {
from: "t_customermasters",
localField: "email",
foreignField: "email",
as: "UserDetails"
}
}, {
$match: {
UserDetails: { $exists: true, $not: {$size: 0} }
}
}
]).pretty();
You need to actually lookup in t_customermasters and project down by conditioning with empty array
db.t_usermasters.aggregate([
{
$match: {
"email" : "test#test.com"
}
},
{
$lookup: {
from: "t_customermasters",
localField:"email",
foreignField:"email",
as: "UserDetails"
}
},
{
$project:{
_id:true,
email:true,
emailExistInBoth:{
$cond:{
if:{
$eq:[{$size:"$UserDetails"},0]
},
then:false,
else:true
}
}
}
},
{
$match:{
"emailExistInBoth":true
}
}
]).pretty();

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