how can i agregate datas from different collections in mongodb using nodejs? - node.js

I am using mongoDB and nodejs
I have 4 collections
collection 1 is teacher with fields teacher_id, teacher_name
collection 2 is subject with fieldssubject _id, subject_name
collection 3 is book with fields book_id, book_name
collection is student which have fields -- _id, student_name, teacher_id, subject_id, book_id
how can I fetch ids from 1, 2, 3 collections simultaneously and insert to corresponding id in collection
I have tried some which always ask for a matching field... is ther any function which returns data from collection even though no match field?
can someone please help

Well, in that case, you need to fetch all the documents from those collections. That will be a bit costly aggregation but I'm adding here in code:
Firstly, I'm grouping on null, to avoid to attach lookup value to every single document in teacher collection.
db.teacher.aggregate([
{
$group:{
"_id":null,
"root":{
$push:"$$ROOT"
}
}
},
{
$lookup:
{
from:"subject",
pipeline: [],
as: "subjectLookup"
}
},
{
$lookup:
{
from:"book",
pipeline: [],
as: "bookLookup"
}
},
{
$lookup:
{
from:"student",
pipeline: [],
as: "studentLookup"
}
}
]).pretty()
These lookups will give the array which contains all the documents from respective collections, you can limit the documents by adding $match stage in the pipeline of lookup stage.
Hope this will solve your problem :)

Related

how to populate to an array inside another shema using mongoose

There are two collections. Catalog collection and order Collection. Catalog collection contains seller id , and compelete product details.
Order collection contains order details like ids of ordered products and buyer details.
My problem is how can I get the complete product details when fetching an order .
order collection is given below
this is the order collection. It contains product Id. I need to get the details of products when fetching orders. Problem is that there is no seperate collection for products. Products are present inside 'catalog' collection
Catalog Collection is given below:
this is the catalog collection.It contains an array of products. so the products are present there
I need to get product details when fetching order details
const order = await Order.find().populate("products");
I am not sure I understand your question entirely but hope should help you:
Plan
unwind products
lookup product with _id of product in catalog.products
unwind the lookup result because result of lookup stage is an array
group this back together
Implementation
const result = await orderModel.aggregate()
.unwind('products')
.lookup({
from: 'catalogs',
let: { product_id: '$products' }, // in order
pipeline: [
{
$unwind: '$products' // $expr cannot digest arrays so we need to unwind which hurts performance...
},
{
$match: { $expr: { $eq: ['$products._id', '$$product_id'] } }
},
{
$project: { _id: 0, products: 1 } // only care products in catelog
}
],
as: 'productDetail'
})
.unwind('productDetail')
.group({
_id: '$_id',
seller: { '$first': '$seller' },
buyer: { '$first': '$buyer' },
products: {
$push: '$productDetail.products'
}
});
However, I don't recommend doing it this way as it can be resource intensive... I suggest you change your database design eg separating product into a separate collection for easier querying.

MongoDB: How to perform a second match using the results (an array of ObjectIds) of the previous match in aggregation pipeline

I have a MongoDB collection called users with documents that look like:
{
_id: ObjectId('123'),
username: "abc",
avatar: "avatar/long-unique-random-string.jpg",
connections: [ObjectId('abc'), ObjectId('xyz'), ObjectId('lmn'), ObjectId('efg')]
}
This document belongs to the users collection.
What I want to do:
First, find one document from the users' collection that matches _id -> '123'.
Project the connections field received from step 1, which is an array of ObjectIds of other users within the same collection.
Find all documents of users from the array field projected in step 2.
Project and return an array of only the username and avatar of all those users from step 3.
While I know that I can do this in two separate queries. First using findOne which returns the friends array. Then, using find with the results of findOne to get all the corresponding usernames and avatars.
But, I would like to do this in one single query, using the aggregation pipeline.
What I want to know, is it even possible to do this in one query using aggregation?
If so, what would the query look like?
What, I currently have:
await usersCollection
.aggregate([
{ $match: { _id: new ObjectId(userId) } },
{ $project: { ids: "$connections" } },
{ $match: { _id: { $in: "ids" } } },
{
$project: {
username: "$username",
avatar: { $ifNull: ["$avatar", "$$REMOVE"] },
},
},
])
.toArray()
I know this is wrong because each aggregation stage receives the results from the previous stage. So, the second match cannot query on the entire users' collection, as far as I know.
I'm using MongoDB drivers for nodeJS. And I would like to avoid $lookup for possible solutions.

Nestjs- How to sum up all the number values of a particular collection of mongodb

I am working on nestjs and I have a collection where 5 documents are saved and each document has a property name 'price'. I want to fetch price property from every document and need to sum up all and shows that sum as an output. How do I achieve this?
Use aggregate
.aggregate([
{
$group: {
_id: '',
sumPrices: { $sum: '$price' }
}
])

Matching array of objects containing an Object using Aggregration framework

This is how data is in my mongodb database.
_id:ObjectId('5c38e514b88edd0ef236c3f7'),
rooms:[
{
info:{
name:'John',
age:'23'
}
},
{
info:{
name:'Mary',
age:'15'
}
}
]
Using aggregation framework, I want to match then 'name' field which is inside the info object of which is in the rooms array. How do I achieve this?
What I have tried so far:
Hotel.aggregate([
{$match: {
'_id':mongoose.Types.ObjectId(lodgeId),
'rooms.info.name':'John'}}
)]
This gives me ALL ROOMS instead of matching the one with name John.
How do I get only the matched row?
If you unwind the rooms array before the match:
Hotel.aggregate([
{$unwind: "$rooms"},
{$match: {
'_id':mongoose.Types.ObjectId(lodgeId),
'rooms.info.name':'John'}}
)]
You should get a document with only the rooms that have the name John.
Unwind turns an array field into a new document for each item in the array.

How should I find a Mongoose subdocument given the parent document and a value in the subdocument?

I'm just trying to do a basic find similar to .findOne, but on a subdocument array in Mongoose. Should I simply loop through the array looking for the right subdocument?
I have a schema like so:
var RegionSchema = new Schema({
"metadata": {
"regionType": String,
"name": String,
"children": [{
"name": String,
"childType": String
}],
"parent": Schema.ObjectId
},
"data": [DataContainer]
});
I know that I want to find a DataContainer in data with dataYear equal to "2014". I'm new to MongoDB, so I don't know many advanced commands. What would be the most efficient way?
EDIT: dataYear is guaranteed to be unique in that array.
Use the aggregation framework for this. Your aggregation pipeline would consist of a $match operation stage which matches documents in the collection where the data array element object has a field dataYear with value equal to "2014". The next pipeline stage would be the $unwind operation on the data array object and a further $match pipeline to filter the arrays. Final stage would be to $project the deconstructed array. For example, suppose you have a model Region that uses the RegionSchema, your mongoose code would be:
Region.aggregate([
// similar query object you use in findOne() can also be applied to the $match
{
"$match": {
"data.dataYear": "2014",
"metadata.name": "example text"
}
},
{
"$unwind": "$data"
},
{
"$match": {
"data.dataYear": "2014"
}
},
{
"$project": {
"_id": 0,
"dataYear": "$data.dataYear",
"population": "$data.population"
}
}
], function(err, docs){
});
You could add an $elemMatch to your query.
Assuming Region is the model:
Region.findOne(...).select({data: {$elemMatch: {dataYear: 2014}});
This will return the Region document with the data array containing only the matching item.
UPDATE: If you already have a document with an array of subdocuments you can use something like lodash's find method to select the subdocument. NOTE: this will convert the subdocument to a POJO.
_.find(region.data.toObject(), {dataYear: 2014});

Resources