I want to populate the ingredientsList.
Is it possible to get the array back with populated ingredients field ?
How I can do it, if I want just one object out of ingredientsList with populated ingredient ?
Hope you can help :)
My Schema looks like this:
export const RecipeSchema = new Schema({
name: {
type: String,
required: 'Enter a name',
},
ingredientsList: [
{
ingredient: {
type: Schema.Types.ObjectId,
ref: 'Ingredient',
},
value: {
type: Number,
default: 1,
},
},
],
});
My Ingredient Model looks like this:
export const IngredientSchema = new Schema({
name: {
type: String,
required: 'Enter a name',
},
created_date: {
type: Date,
default: Date.now,
},
amount: {
type: Number,
default: 1,
},
});
As the field, ingredientsList, is an array of referenced documents from the Ingredient collection - you can use model.populate() as follows:
const recipes = await Recipe.find().populate('ingredientsList');
res.send({ data: orders });
This will return all Recipes and also expand or populate the ingredientsList for each.
Let's say that you only wanted populate the name field of each document in ingredientsList - you do so as follow:
const recipes = await Recipe.find().populate('ingredientsList', 'name');
res.send({ data: orders });
This will return all Recipes but only populate the name field on ingredientsList for each.
Mongoose docs on population
Related
Suppose you have two mongoose schemas: Meal and Ingredient.
Meal
const mealSchema = new mongoose.Schema({
title: { type: String },
ingredients: [{
ingredient: { type: mongoose.Types.ObjectId, required: true, ref: 'Ingredient' },
amount_grams: { type: Number, required: true }
}],
});
Ingredient
const ingredientSchema = new mongoose.Schema({
name: { type: String, required: true },
kcal_per_gram: { type: Number, required: true },
});
Before every save and update, I want to calculate the kcal property and assign it to the Meal model. The pseudocode for calculation is this:
let sum_kcal = 0;
for (ingr of ingredients) {
sum_kcal += ingr.ingredient.kcal_per_unit * ingr.amount;
}
I can't use a virtual property, because I need the user to be able to sort and filter by kcal.
I have a collection called Orders that contains this schema:
const mongoose = require('mongoose');
const orderSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
restaurant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Restaurant',
required: true
},
dishes: [
{
dish: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Dish'
},
amount: Number
}
],
price: {
type: Number,
required: true
},
comment: {
type: String,
required: false
},
status: {
type: String,
enum: ['PROCESSING', 'CANCELLED', 'COMPLETED', 'ERROR'],
default: 'PROCESSING'
},
timestamp: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema);
Inside my router, I have this code:
let orders = await Order.find({restaurant: restaurantID, status:'PROCESSING'}).populate('dishes._id').exec()
Order.find does not throw an exception, but it isnt working either.
I want the res.body to look like this:
{
"_id": "objectID",
"user": "objectID",
"restaurant": "objectID",
"dishes": [
{
"amount": number,
"dish": {
//dish object
}
},
...
],
//other order properties
},
...
]
But for some reason the dishes array looks like this:
"dishes": [
{
"amount": 1,
"_id": "6184e848e6d1974a0569783d"
}
],
What am I doing wrong?
I know that if populate() worked the res.body dishes array would not have a property called 'dish' and instead have a property called _id that would contain the dish object, but this shouldnt be hard to change once populate() works.
EDIT:
I realised that my createOrder route could be part of the problem since it ignores my schema and uses an id property for the objectID instead of dish. The array I save to the DB contains a property called id for the id instead of dish, but shouldnt my schema throw an exception when i try to save something like this to my database?
At first glance, I think the problem might be that you have a syntax problem.
Try
.populate('dishes').exec()
instead of
.populate('dishes._id').exec()
I have an array of objectIDs references in mongo. I want to get a specific element in that array after populating the objectIDs. the problem is i get an empty array.
Here's my schema
// Patient Schema - start
const patientSchema = new mongoose.Schema({
nom: {
type: String,
required:true
},
prénom: {
type: String,
required:true
},
naissance:{
type:Date,
},
adresse: {
type: String,
required:true
},
téléphone: {
type: String,
required:true
},
profession: {
type: String,
},
/// the field i'm trying to populate
consultations:[{
type: mongoose.Schema.Types.ObjectId,
ref:'Consultation'
}],
salle:{
type: mongoose.Schema.Types.ObjectId,
required: true,
ref:'Salle'
},
date:{
type:String,
default: Date.now
},
jointes: {
type:Array
},
questionnaire: {
type:Object
},
}, { collection : 'patients'} );
const patients = mongoose.model('Patient', patientSchema);
Consultation schema
const consultationSchema = new mongoose.Schema({
date: {
type: String,
required:true
},
motif:{
type: String,
},
observations: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Observation"
}],
paiements: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Paiement"
}],
ordonnances: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Ordonnance"
}]
});
const consultations = mongoose.model('Consultation', consultationSchema);
the exports
module.exports = {
patients: patients,
consultations: consultations,
}
The router where i'm trying to populaet consultation field and then get the item
const {patients} = require('./patient.models')
const {consultations} = require('./patient.models')
// not working , getting empty array
const patient = await patients.find({"consultations.motif" : "Checking"}).populate('consultations')
res.send(patient)
The mongo db record , to show you that the field does exist
Here's what i get when i do make the following query iwthout specifiying the field
const patient = await patients.find().populate('consultations')
res.send(patient)
This question already has been answered here: Find after populate mongoose
Here is the solution for your case which does not involve changing the database structure:
const patient = await patients.find().populate({
path: 'consultations',
match: {
motif: 'Checking'
}
})
res.send(patient)
Background
Here's part of my User model:
const Group = require("./Group")
...
groups: {
type: [{ type: Schema.ObjectId, ref: Group }],
default: [],
},
And here's my Group model:
module.exports = mongoose.model(
"Group",
new Schema(
{
name: {
type: String,
required: true,
unique: true,
},
/**
* Array of User ObjectIDs that have owner rights on this group
*/
owners: {
type: [{ type: Schema.ObjectId, ref: User }],
default: [],
},
},
{
timestamps: true,
}
)
)
The Code
Here's the code I'm running to try and populate:
const user = await (await User.findOne({ _id: ... })).execPopulate("Group")
console.log(user.groups)
My console.log is outputting an array of object IDs, when I'd like it to output an actual Group document.
Attempted solutions
I've tried changing my ref to be using the string ("Group"), I've tried arranging my query differently, etc. I'm not sure how I'd go about doing this.
Apologies in advance if this is a duplicate, I've done my best to search but can't really find a solution that works for me.
Specifically, what do I need help with?
I'm trying to create a 'link' between a user model and a group model. In my console.log, I expect it to output a Group document; but it outputs an object ID (which is how it's stored raw in the database, meaning that Mongoose isn't transforming it correctly)
When you change execPopulate to populate like:
async function findUserAndPopulate(userId){
const response = await User.findOne({
_id: userId,
}).populate('groups')
console.log("response",response)
}
You got:
{
groups: [
{
owners: [Array],
_id: 5ecc637916a2223f15581ec7,
name: 'Crazy',
createdAt: 2020-05-26T00:31:53.379Z,
updatedAt: 2020-05-26T00:31:53.379Z,
__v: 0
}
],
_id: 5ecc6206820d583b99b6b595,
fullname: 'James R',
createdAt: 2020-05-26T00:25:42.948Z,
updatedAt: 2020-05-26T00:36:12.186Z,
__v: 1
}
So you can access the user.groups
See the doc: https://mongoosejs.com/docs/populate.html
Here is my problem I have two schemas one nested in another as an array. I am trying to push into the array and save the subdocument but it is not saving properly, I get an object that is saved but none of the fields are saved except for its _id. Do I have to save each model individually first? What is the issue here?
Here are my two schemas:
import mongoose from "mongoose";
import {contactSchema} from "./ContactSchema"
export const bigSchema = new mongoose.Schema({
testField: {
type: String,
required: true,
},
contacts: [{ contactSchema }],
}
});
export default mongoose.model("Big", bigSchema);
import mongoose from "mongoose";
export const contactSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
age: {
type: number,
required: false,
}
});
export default mongoose.model("Contact", contactSchema);
Here is my code that I use to push to the array of contacts.
public async saveContact(
testField: string,
name: string,
age: number,
) {
const newContact = new Contact({
name: name,
age: age,
});
console.log(newContact);
return UserContacts.findOneAndUpdate(
{
testField: testField,
},
{ $push: { contacts: newContact } },
{ new: true, upsert: true }
);
}
However when I check my database, this is what I see instead. There is an objectId but not what I expect to see, which is a list of Contact subdocuments inside my "Big" document
{
"_id" : ObjectId("XXXX"),
"testField" : "XXXXX",
"contacts" : [
{
"_id" : ObjectId("XXXXX")
}
],
"__v" : 0
}
export const bigSchema = new mongoose.Schema({
testField: {
type: String,
required: true,
},
contacts: [{ contactSchema }],
}
});
should be:
export const bigSchema = new mongoose.Schema({
testField: {
type: String,
required: true,
},
contacts: [contactSchema],
}
});
Try that and see what happens.
Edit: Also, if you intend for contacts to be an array of references to the Contact model, then you need to do this instead:
export const bigSchema = new mongoose.Schema({
testField: {
type: String,
required: true,
},
contacts: [{type: mongoose.Schema.Types.ObjectId, ref: 'Contact'}],
}
});}
This will make contacts an array of Contact IDs, so you're not duplicating any data, but just referencing the contacts in their collection. docs