Mongoose deep populate() returns empty array - node.js

I need a help on mongoose deep population. Basically, I have an ItemGroupSchema having a _id referenced to ItemSchema and items being an array of references to ItemSchema as well.
const ItemSchema = new mongoose.Schema<IItem>({
// information fields about item type, quantity, model, size,...
}); // its model is ItemModel
const ItemGroupSchema = new mongoose.Schema<IItemGroup>({
_id: { type: mongoose.Schema.Types.ObjectId, required: true, ref: ItemModel.modelName },
items: [{ type: mongoose.Schema.Types.ObjectId, ref: ItemModel.modelName }]
}, { _id: false }); // its model is ItemGroupModel
From a valid _id input, I do the following:
Get the items of it from ItemGroupModel; done.
With the items of _id I got, I populate it from ItemGroupSchema so I can have items of items of _id; done.
Now, I should have items of items inside items of _id. Next is to populate only on items of _id from ItemSchema to have some information to work on, which is not done yet.
The issue is that, populate() operation of the last step gives me an empty items array. Below is how each operation looks like step by step:
1.
ItemGroupModel.find({ _id: 'root' });
{
_id: 'root',
items: ['parent1', 'parent2']
}
2.
ItemGroupModel.find({ _id: 'root' }).populate({ path: 'items', model: ItemGroupModel.modelName });
{
_id: 'root',
items: [
{ _id: 'parent1', items: ['child1', 'child2'] },
{ _id: 'parent2', items: ['child3']
]
}
3.
ItemGroupModel.find({ _id: 'root' }).populate({ path: 'items', model: ItemGroupModel.modelName, populate: { path: '_id', model: ItemModel.modelName }});
{
_id: 'root',
items: [] // yes, empty
}
// I expect it to be
{
_id: 'root',
items: [
{ _id: { _id: 'parent1', type: 'gun', quantity: 1, size: 1 }, items: ['child1', 'child2'] },
{ _id: { _id: 'parent2', type: 'backpack', quantity: 1, size: 1 }, items: ['child3']
]
}

use this aggregation on ItemSchema collection
[{
from: 'ItemGroup',
localField: 'items',
foreignField: '_id',
as: 'items'
}]

Related

find object by id which is in array mongoose

My chat object has got an array with two elements - users id. I have first id from url params, but second id I have in array of users. Now I want to get all chats where first id is this one from url, and second is in the array. I think that example how I tried to do it will be the best explanation of this problem :
Chat.find({
users: { $all: [req.params.id, { $in: usersIdArray }] }
})
where usersIdArray is for example:
[ 5f8777a01d8c122e74cb6f08, 5f8777721d8c122e74cb6f02 ]
they are numbers, not strings. I don't know if it is important...
The error I get now :
(node:12168) UnhandledPromiseRejectionWarning: CastError: Cast to ObjectId failed for value "{ '$in': [ 5f8777a01d8c122e74cb6f08, 5f8777721d8c122e74cb6f02 ] }" at path "users" for model "Chat"
And my chat schema:
// Create schema
const ChatSchema = new Schema({
users: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Users',
}, {
type: Schema.Types.ObjectId,
ref: 'Users',
}],
required: [true, 'Podaj uczestników czatu.'],
},
lastMessage: {
type: Schema.Types.ObjectId,
ref: 'Message'
}
}, { timestamps: opts });
Since the length of your array is fixed (2), you can just query based on array position:
Chat.find({
"users.0": req.params.id,
"users.1": {$in: usersIdArray}
});
If that doesn't work then probably because usersIdArray are actually not ObjectIds, in which case you'd need to map them:
usersIdArray.map(x => ObjectId(x))
#Christian Fritz, I had to add $or to your solution and everything is fine now:
Chat.find({
$or: [
{
"users.1": req.params.id,
"users.0": { $in: usersIdArray }
}, {
"users.0": req.params.id,
"users.1": { $in: usersIdArray }
}]
})

Mongoose: Find all Models using array of objects

I have this Model:
const cart = new mongoose.Schema(
{
products: [{
productId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Product",
},
quantity: {
type: Number,
required: true,
default: 1
},
title: String,
price: Number
}],
},
{ timestamps: true });
How I find all my products (from Model Product) using it.
cart = Cart.find(id);
// inside cart.products
[{productId: 'asvhbajAS13', quantity: 8 },{productId: 'asvhbajAS13', quantity: 2 }]
I want to modify all products after that, is this approach right?
What I've tried:
Product.find({
'_id': { $in: { cart.products } }
}, function(err, product) {
})
});
your code is correct but if you use findOne() .or you can use populate instead of query once more :
cart = Cart.find(id).populate("products")

Populating array of collection which contains references to another collections returns empty array

I have two models Vote and Link,I am trying to populate the votes array in link model,The votes array contains id's that references to the collection Vote,which only contains two fields link and User which also refs to same link model mentioned below and a user model respectively
link Schema:-
const linkSchema = new mongoose.Schema(
{
description: {
type: String,
trim: true,
},
url: {
type: String,
trim: true,
},
postedBy: {
type: mongoose.Types.ObjectId,
ref: "User",
},
votes: [{ type: mongoose.Types.ObjectId, ref: "Vote" }],
},
{
timestamps: true,
}
);
linkSchema.index({ description: "text" });
linkSchema.index({ createdAt: -1 });
module.exports = mongoose.model("Link", linkSchema);
Vote schema:-
const mongoose = require("mongoose");
const voteSchema = new mongoose.Schema({
link: { type: mongoose.Types.ObjectId, ref: "Link" },
user: { type: mongoose.Types.ObjectId, ref: "User" },
});
module.exports = mongoose.model("Vote", voteSchema);
but when i try to get the votes of a link,it always return an empty array ,My function:-
const votes = async ({ id }) => {
const linkData = await Link.findById(id).populate("votes").exec();
console.log(linkData);
};
Output Data:-
{
votes: [], //empty always
_id: 5ecb21059a157117c03d4fac,
url: 'https://www.apollographql.com/docs/react/',
description: 'The best GraphQL client for React',
postedBy: 5ec92a58bf38c32b38400705,
createdAt: 2020-05-25T01:36:05.892Z,
updatedAt: 2020-05-25T01:37:52.266Z,
__v: 0
}
Instead of populate(), you can use aggregate() to get your desired output. This should probably work in your case:
Link.aggregate([
{
$match: {
_id: { $in: [mongoose.Types.ObjectId(id)] // as suggested by the questioner
}
},
{
$lookup: {
from: "vote", // collection to join
localField: "votes", // field from the input documents (filtered after _id is matched)
foreignField: "link", // field to compare with, from other collection
as: "linkData" // output array name
}
}
])
Let me know in the comments.

mongoose populate sort _ Mongoose Node.js

I have two schemas that represent my post and category documents. I'm trying to sort my posts with category.order property. order property is a number field.
const postSchema = mongoose.Schema({
title: {
type: String,
max: 200,
},
body: {
type: String,
max: 10000,
},
categories: {
type: mongoose.Schema.ObjectId,
ref: 'Category',
required: true
}
})
module.exports = mongoose.model('Post', postSchema);
const categorySchema = mongoose.Schema({
name: {
type: String,
max: 30,
required:true
},
order: {
type: Number,
unique: true
},
})
module.exports = mongoose.model('Category', categorySchema);
I know sort only works with numeric fields. I searched a lot about the simular problem in web and StackOverflow even the mongoose documention.but my query doesn't work. it gets my post back but sorting order is not working.
query:
Post.find({}).populate({path:'categories', select:'order', options:{sort:{order:1}}})
Well populate does not sort the root/outer documents. The options passed in the populate only sorts the inner referenced documents. You have to use aggregation here to make sorting on the parent documents and that's what $lookup can better do as compared to populate queries.
Post.aggregate([
{ '$lookup': {
'from': 'categories',
'let': { 'categories': '$categories' },
'pipeline': [
{ '$match': { '$expr': { '$eq': ['$_id', '$$categories'] }}},
{ '$project': { 'order': 1 }}
],
'as': 'categories'
}},
{ '$unwind': '$categories' },
{ '$sort': { 'categories.order': 1 }}
])

mongoose how to perform aggregation on ref fields

How to perform aggregation in mongoose on the fields that are based on ref's of other schema..
eg : below id the schema
var StorySchema = new Schema({
_creator : { type: Schema.ObjectId, ref: 'Person' }
, title : String
, fans : [{ type: Schema.ObjectId, ref: 'Person' }]
});
how to perform aggregation with creator and fans
thanks in advance
You can use populate function, document: http://mongoosejs.com/docs/populate.html
populate will help you lookup data base on the ObjectIds and the ref collections:
Story
.findOne({title: 'your title'})
.populate(['_creator', 'fans'])
.exec(function (err, doc) {
console.log(doc);
})
Output:
{ _id: 52b9768a8a770b383d000003,
title: 'your title',
_creator: { name: 'user1', _id: 52b975e13e7f2dec31000001, __v: 0 },
fans:
[ { name: 'fan1', _id: 52b975e13e7f2dec31000001, __v: 0 },
{ name: 'fan2', _id: 52b975e13e7f2dec31000002, __v: 0 },
{ name: 'fan3', _id: 52b975e13e7f2dec31000003, __v: 0 }] }
you can remove populate function to see the different on result

Resources