How to get data from dynamic mongoID with aggregate in mongodb - mongodb

Here is have two collections
Product
individual Product stock (collectionname is like mongoID)
1.Product collection
db.getCollection("products").insert({ _id:"60dcc2f4c8b03e500a019fda",
"name":"mobile"
})
2 dynamicID collection
db.getCollection("60dcc2f4c8b03e500a019fda").insert(
{ quantity:5,product:"60dcc2f4c8b03e500a019fda" }
)
My Query is like
db.getCollection('products').aggregate([{
$lookup: {
from: '_id',
localField: '_id',
foreignField: 'product',
as: 'stocks'
}
},
])
Getting blank Array

As of now, you can't dynamically lookup collections.
The from field cannot be an expression and must be a string literal.
There is an open feature request for this however it seems it is very unlikely to happen:
Thanks to everyone for voting and giving your input on this request. Currently, there are no plans for supporting variable `from' collection per document, that would require significant changes in the security and query optimization architectures.

Your second insert statement inserted into a collection called "60dcc2f4c8b03e500a019fda". Your $lookup refers to a non-existent collection called "_id". To make this work try this...
Insert into 2 collections...
db.getCollection("products").insert({
_id:"60dcc2f4c8b03e500a019fda",
"name":"mobile"
})
db.getCollection("inventoryStock").insert({
quantity:5,
product:"60dcc2f4c8b03e500a019fda"
})
Run Aggregation...
db.getCollection('products').aggregate([
{
$lookup:
{
from: 'inventoryStock',
localField: '_id',
foreignField: 'product',
as: 'stocks'
}
}
])
Output:
{ "_id" : "60dcc2f4c8b03e500a019fda", "name" : "mobile", "stocks" : [ { "_id" : ObjectId("60e0ffff1e165946802c244a"), "quantity" : 5, "product" : "60dcc2f4c8b03e500a019fda" } ] }

Related

how to sort a mongoDB collection based on mapped value

a simple question (hopefully) to mongoDB users
i have 2 collection
collection A have a data with ID which the name (describing the ID) located in collection B.
i would like to query mongo to get all the Items from Collection A sorted ASC by the mapped name from Collection B.
TIA
well,
i found a simple solution for it:
db.createCollection("ColA")
db.createCollection("ColB")
db.ColA.insert({name:"Item1",priorityid:1})
db.ColA.insert({name:"Item2",priorityid:2})
db.ColA.insert({name:"Item3",priorityid:3})
db.ColA.insert({name:"Item4",priorityid:1})
db.ColA.insert({name:"Item5",priorityid:2})
ColA:
{"_id":"5fd7c79f774870001fa36872","name":"Item1","priorityid":1}
{"_id":"5fd7c7a9774870001fa36873","name":"Item2","priorityid":2}
{"_id":"5fd7c7bb774870001fa36875","name":"Item3","priorityid":3}
{"_id":"5fd7c7c8774870001fa36876","name":"Item4","priorityid":1}
{"_id":"5fd7c7d5774870001fa36877","name":"Item5","priorityid":2}
db.ColB.insert({name:"b_high",priorityid:1})
db.ColB.insert({name:"a_medium",priorityid:2})
db.ColB.insert({name:"c_low",priorityid:3})
ColB:
{"_id":"5fd7c810774870001fa3687b","name":"b_high","priorityid":1}
{"_id":"5fd7c842774870001fa3687c","name":"a_medium","priorityid":2}
{"_id":"5fd7c851774870001fa3687d","name":"c_low","priorityid":3}
Query:
db.ColA.aggregate([
{
$lookup:
{
from: "ColB",
localField: "priorityid",
foreignField: "priorityid",
as: "priorityname"
}
}, { $unwind:"$priorityname" }, {
$project:{
_id : 1,
name : 1,
priorityname : "$priorityname.name"
}
},{ $sort : { priorityname : 1 } }
])
result:
{"_id":"5fd7c7a9774870001fa36873","name":"Item2","priorityname":"a_medium"}
{"_id":"5fd7c7d5774870001fa36877","name":"Item5","priorityname":"a_medium"}
{"_id":"5fd7c79f774870001fa36872","name":"Item1","priorityname":"b_high"}
{"_id":"5fd7c7c8774870001fa36876","name":"Item4","priorityname":"b_high"}
{"_id":"5fd7c7bb774870001fa36875","name":"Item3","priorityname":"c_low"}

Why MongoDb sort is slow with lookup collections

I have two collections in my mongodb database as follows:
employee_details with approximately 330000 documents which has department_id as a reference from departments collection
departments collections with 2 fields _id and dept_name
I want to join the above two collections using department_id as foreign key by using lookup method. Join works fine but the mongo query execution takes long time when I add sort.
Note: The execution is fast If I remove the sort object or If I remove the lookup method.
I have referred several posts in different blogs and SO, but none of them give a solution with sort.
My query is given below:
db.getCollection("employee_details").aggregate([
{
$lookup: {
from: "departments",
localField: "department_id",
foreignField: "_id",
as: "Department"
}
},
{ $unwind: { path: "$Department", preserveNullAndEmptyArrays: true } },
{ $sort: { employee_fname: -1 } },
{ $limit: 10 }
]);
Can someone give a method to make the above query to work without delay, as my client cannot compromise with the performance delay. I hope there is some method to fix the performance issue as nosql is intented to handle large database.
Any indexing methods is available there? so that I can use it along with my same collection structure.
Thanks in advance.
Currently lookup will be made for every employee_details which means for 330000 times, but if we first sort and limit before lookup, it will be only 10 times. This will greatly decrease query time.
db.getCollection('employee_details').aggregate([
{$sort : {employee_fname: -1}},
{$limit :10},
{
$lookup : {
from : "departments",
localField : "department_id",
foreignField : "_id",
as : "Department"
}
},
{ $unwind : { path: "$Department", preserveNullAndEmptyArrays: true }},
])
After trying this, if you even want to decrease the response time you can define an index on the sort field.
db.employee_details.createIndex( { employee_fname: -1 } )

MongoDB create a filtered collection with 2 collections data

I have a mongo database that consist of huge github data (users, issues, repos, etc).
I want to create small collections from this big data.
I sorted "users" collection according to "followers" count of users.
Then I got the first 1000 users from this query.
db.getCollection("users").find({}).sort({followers:-1}).limit(1000).forEach(function(doc){
db.usersnew.insert(doc);});
There is another collection called "repos" that consists of info about users' repository. (user key field :"owner.id" )
I want to create a new filtered repos collection which consists only users who present in usersnew collection.
I tried to use $look_up but it works like join.
db.getCollection('reposnew').aggregate([{
$lookup:
{
from: "users",
localField: "owner:id",
foreignField : "id",
as: "filteredRepo"
}
}])
It creates users collection + repos in a one collection.
I want only filtered repos collection with specific users' data.
You're on the right track, you just need to add an $out stage.
db.getCollection('reposnew').aggregate([
{
$lookup:
{
from: "users",
localField: "owner.id",
foreignField : "id",
as: "filteredRepo"
}
},
{
$match: {
"filteredRepo.0": {$exists: true}
}
},
{
$project: {
filteredRepo: 0
}
},
{
$out: "newCollectionName"
}
])

$lookup : computed foreinField workaround?

For an existing mongo database, the link between 2 collections is done by :
collA : field collB_id
collB : field _id = ObjectId("a string value")
where collB_id is _id.valueOf()
i.e. : the value of collB_id of collA is "a string value"
but in a $lookup :
localField: "collB_id",
foreignField: _id.valueOf(),
don't work, so what can I do ?
Mongodb v3.6
If i understood you correctly, you have two collections where documents from first collection (collA) reference documents from second collection (collB). And the problem is that you store reference as a string value of that objectId, so you cant use $lookup to join those docs.
collA:
{
"_id" : ObjectId(...),
"collB_id" : "123456...",
...
}
collB:
{
"_id" : ObjectId("123456..."),
...
}
If you are using mongo 4.0+ you can do it with following aggregation:
db.getCollection('collA').aggregate([
{
$addFields: {
converted_collB_id: { $toObjectId: "$collB_id" }
}
},
{
$lookup: {
from: 'collB',
localField: 'converted_collB_id',
foreignField: '_id',
as: 'joined'
}
}
]);
Mongo 4.0 introduces new aggregation pipeline operators $toObjectId and $toString.
That allows you to add new field which will be an ObjectId created from the string value stored in collB_id, and use that new field as localField in lookup.
I would strongly advise you not to store ObjectIds as strings.
You already experienced the problem with $lookup.
Also, size of ObjectId is 12 bytes while its hex representation is 24 bytes (that is twice the size). You will probably want to index that field as well, so you want it to be as small as possible.
ObjectId also contains timestamp which you can get by calling getTimestamp()
Make your life easier by using native types when possible!
Hope this helps!

Mongodb $lookup on multiple fields

I have two collections, products and properties.
I'm doing a lookup such as:
[{
$match: {
category_id: mongoose.Types.ObjectId(category_id)
}
},
{
$lookup: {
from: "properties",
localField: "category_id",
foreignField: "category_id",
as: "properties"
}
}
]
This is basically getting me all of the products that match the category_id and including the properties that match the same category_id.
I need to add an additional check, for some_id on the properties result. In otherwords, the properties should be grouped by the some_id that is returned from the products collection and matches the same key in properties. Does that make sense? Basically having the ability to have multiple local/foreign field definitions.
any idea how I could this?
Since version 3.6 we can use uncorrelated sub-queries
{
$lookup:
{
from: '<collection to join>',
let: { <var_1>: '<expression>', …, <var_n>: '<expression>' },
pipeline: [ '<pipeline to execute on the collection to join>' ],
as: <output array field>
}
}
This allows us to to have more than a single equality match on the lookup.
See also: https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/