My first collection value is :
Collection 1:
{
_id:"5f82f1618cfa6d290c6271a9",
name:"mehdi"
}
And second collection value is :
Collection 2:
{
_id:"5f82f1618cfa6d290c6271aa",
fid:"5f82f1618cfa6d290c6271a9",
family:"parastar"
}
How can I populate base on _id in coll1 and fid in coll2?
I want to be, result like this:
{
{
_id:"5f82f1618cfa6d290c6271aa",
fid:"5f82f1618cfa6d290c6271a9",
family:"parastar"
},
name:"mehdi"
}
do you have any idea to do this?
You have to use $lookup in this way:
db.coll1.aggregate([
{
$lookup: {
from: "coll2",
localField: "_id",
foreignField: "fid",
as: "collection"
}
}
])
This query create a field called collection with the data you want:
[
{
"_id": "5f82f1618cfa6d290c6271a9",
"collection": [
{
"_id": "5f82f1618cfa6d290c6271aa",
"family": "parastar",
"fid": "5f82f1618cfa6d290c6271a9"
}
],
"name": "mehdi"
}
]
Example here
Using Mongoose is the same, only write the query like this:
var agg = await model.aggregate([
{
$lookup: {
from: "coll2",
localField: "_id",
foreignField: "fid",
as: "collection"
}
}
])
console.log(agg)
Related
I'm trying to get the last data inserted in my collection using MongoDB. This is my code:
dht11.aggregate(
[
{
$lookup:
{
from: "storage_rooms",
localField: "node",
foreignField: "name",
as: "MainStorage"
}
},
{ $unwind: "$MainStorage"},
{ $match: {node: "Main Storage"} },
]
).sort({$natural:-1}).limit(1);
I have 2 collections I want to combine using lookup.
Collection1: _AddressSyncStatus
fields I wanna use from this collection: "address"
Collection2: EthTokenTransfers
Fields I want to use from this collection: "to_address", "from_address".
Now when I use mongo compass, the lookup filter expects a local field, in my case the local field of EthTokenTransfers to join the collections. My problem now is, that I want to lookup where address from _AddressSyncStatus is either EthTokenTransfers.from_address OR EthTokenTransfers.to_address.
Is this possible using aggregations?
{
from: '_AddressSyncStatus',
localField: 'string', //from_address OR to_address
foreignField: 'address',
as: 'synced_address'
}
One way to do it is using the $lookup pipeline with $or:
db.EthTokenTransfers.aggregate([
{
$lookup: {
from: "_AddressSyncStatus",
let: {
from_address: "$from_address",
to_address: "$to_address"
},
pipeline: [
{
$match: {
$expr: {$or: [{$eq: ["$_id", "$$from_address"]},
{$eq: ["$_id", "$$to_address"]}
]
}
}
}
],
as: "synced_address"
}
}
])
As you can see here.
But I think that for the rset of the work with this data, it will be more convenient like this:
db.EthTokenTransfers.aggregate([
{
$lookup: {
from: "_AddressSyncStatus",
localField: "from_address",
foreignField: "_id",
as: "synced_address_from"
}
},
{
$lookup: {
from: "_AddressSyncStatus",
localField: "to_address",
foreignField: "_id",
as: "synced_address_to"
}
}
])
As you can see here
I want to know how can i lookup with match.
I could lookup two collection by this query.
db.category.aggregate([
{
$lookup:
{
from: "faq",
localField: "_id",
foreignField: "category_code",
as: "faq"
}
}
])
Then i get this result.
{
"_id":ObjectId("1234"),
"category_name":"about account",
"faq": [
{
"_id":ObjectId("faq id blah blah"),
"category_code" : ObjectId("1234"),
"faq_title":"When you can't create account",
"del_flg":"N"
},
{
"_id":ObjectId("faq id blah blah2222"),
"category_code" : ObjectId("1234"),
"faq_title":"When you change your account",
"del_flg":"N"
},
{
"_id":ObjectId("faq id blah blah3333"),
"category_code" : ObjectId("1234"),
"faq_title":"When you lost your account",
"del_flg":"Y"
}
[
}
I want just two faq item which "del_flg" is "N"
I am not familiar to use mongodb.
Is it possible if i use pipline? I tried some pipline examples, but i couldn't.
You should try $lookup with pipeline,
let will create a variable to access id inside lookup pipeline using $$
pipeline match using $expr because we are comparing both fields $$id = $category_code
set match condition del_flg: N
db.category.aggregate([
{
$lookup: {
from: "faq",
let: {
id: "$_id"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$$id",
"$category_code"
]
},
"del_flg": "N"
}
}
],
as: "faq"
}
}
])
Playground: https://mongoplayground.net/p/gUVUMk6KIAV
I have a collection matches like this. I'm using players object {key: ObjectId, key: ObjectID} instead of classic array [ObjectId, ObjectID] for reference players collection
{
"_id": ObjectId("5eb93f8efd259cd7fbf49d55"),
"date": "01/01/2020",
"players": {
"home": ObjectId("5eb93f8efd259cd7fbf49d59"),
"away": ObjectId("5eb93f8efd259cd7fbf49d60")
}
},
{...}
And players collection:
{
"_id": ObjectId("5eb93f8efd259cd7fbf49d59"),
"name": "Roger Federer"
"country": "Suiza"
},
{
"_id": ObjectId("5eb93f8efd259cd7fbf49d60"),
"name": "Rafa Nadal"
"country": "España"
},
{...}
What's the better way to do mongoDB lookup? something like this is correct?
const rows = await db.collection('matches').aggregate([
{
$lookup: {
from: "players",
localField: "players.home",
foreignField: "_id",
as: "players.home"
}
},
{
$lookup: {
from: "players",
localField: "players.away",
foreignField: "_id",
as: "players.away"
},
{ $unwind: "$players.home" },
{ $unwind: "$players.away" },
}]).toArray()
I want output like this:
{
_id: 5eb93f8efd259cd7fbf49d55,
date: "12/05/20",
players: {
home: {
_id: 5eb93f8efd259cd7fbf49d59,
name: "Roger Federer",
country: "Suiza"
},
away: {
_id: 5eb93f8efd259cd7fbf49d60,
name: "Rafa Nadal",
country: "España"
}
}
}
{...}
You can try below aggregation query :
db.matches.aggregate([
{
$lookup: {
from: "players",
localField: "players.home",
foreignField: "_id",
as: "home"
}
},
{
$lookup: {
from: "players",
localField: "players.away",
foreignField: "_id",
as: "away"
}
},
/** Check output of lookup is not empty array `[]` & get first doc & write it to respective field, else write the same value as original */
{
$project: {
date: 1,
"players.home": { $cond: [ { $eq: [ "$home", [] ] }, "$players.home", { $arrayElemAt: [ "$home", 0 ] } ] },
"players.away": { $cond: [ { $eq: [ "$away", [] ] }, "$players.away", { $arrayElemAt: [ "$away", 0 ] } ] }
}
}
])
Test : mongoplayground
Changes or Issues with current Query :
1) As you're using two $unwind stages one after the other, If anyone of the field either home or away doesn't have a matching document in players collection then in the result you don't even get actual match document also, But why ? It's because if you do $unwind on [] (which is returned by lookup stage) then unwind will remove that parent document from result, To overcome this you need to use preservenullandemptyarrays option in unwind stage.
2) Ok, there is another way to do this without actually using $unwind. So do not use as: "players.home" or as: "players.away" cause you're actually writing back to original field, Just in case if you don't find a matching document an empty array [] will be written to actual fields either to "home" or "away" wherever there is not match (In this case you would loose actual ObjectId() value existing in that particular field in matches doc). So write output of lookup to a new field.
Or even more efficient way, instead of two $lookup stages (Cause each lookup has to go through docs of players collection again & again), you can try one lookup with multiple-join-conditions-with-lookup :
db.matches.aggregate([
{
$lookup: {
from: "players",
let: { home: "$players.home", away: "$players.away" },
pipeline: [
{
$match: { $expr: { $or: [ { $eq: [ "$_id", "$$home" ] }, { $eq: [ "$_id", "$$away" ] } ] } }
}
],
as: "data"
}
}
])
Test : mongoplayground
Note : Here all the matching docs from players which match with irrespective of away or home field will be pushed to data array. So to keep DB operation simple you can get that array from DB along with actual matches document & Offload some work to code which is to map respective objects from data array to players.home & players.away fields.
I'm faced into the issue when I'm trying to merge the results of two MongoDB lookup's into one property, and then I want to unwind them and sort.
I have a problem with merging the results of lookup's.
Here is the actual code:
db.getCollection('collectionA').aggregate([
{
$lookup:
{
from: 'collectionB',
localField: "_id",
foreignField: "collectionAKey",
as: "collectionBInfo"
}
},
{
$lookup:
{
from: 'collectionC',
localField: "_id",
foreignField: "collectionAKey",
as: "collectionCInfo"
}
},
/// then I just want to create one property from both of lookup's, unwind them and sort by the timestamp
{
$unwind: "$mergedCollectionsAandB"
},
{
$sort: {
"mergedCollectionsAandB.timestamp": -1
}
}
])
Here is a models of collections:
CollectionA
_id
name
CollectionB
_id
timestamp
collectionAKey
CollectionC
_id
timestamp
collectionAKey
I assume that it's possible by using $mergeObjects MongoDB operator, but I'm stuck a little bit how to do it in a right way. Is that possible? Thanks in advance.
So the final version of my query looks like that, it's what I was looking for:
db.getCollection('collectionA').aggregate([
{
$lookup:
{
from: 'collectionB',
localField: "_id",
foreignField: "collectionAKey",
as: "collectionBInfo"
}
},
{
$lookup:
{
from: 'collectionC',
localField: "_id",
foreignField: "collectionAKey",
as: "collectionCInfo"
}
},
{
$project: {
"mergedCollectionsAandB": { $concatArrays: ["$collectionBInfo", "$collectionCInfo"] }
}
},
{
$unwind: "$mergedCollectionsAandB"
},
{
$sort: {
"mergedCollectionsAandB.timestamp": -1
}
}
])