Populate a single embedded document - node.js

I have a user model that contains a single embedded document address that is defined like this:
let userSchema = new Schema({
id: ObjectId,
//...
address: {
type: AddressSchema,
required: true,
default: () => ({})
},
//...
});
const UserModel = mongoose.model('User', userSchema);
The Address contains a reference for a Country model:
let AddressSchema = new Schema({
country: {
type: Schema.Types.ObjectId,
ref: 'Country'
}
});
const AddressModel = mongoose.model('Address', AddressSchema);
Where the Country definition is:
let countrySchema = new Schema({
id: ObjectId,
name: {
type: String,
required: true,
unique: true
}
});
const CountryModel = mongoose.model('Country', countrySchema);
And this is how I am populating the user documents:
let user = await UserModel
.findByIdAndUpdate(
someId,
operators,
{ new: true }
)
.populate({
path: 'address.country',
model: CountryModel
})
When I am running a console.log(JSON.stringify(user.address)), the object is not well fetched, as you may see in the comment of the code below, there is an additional _id field that I don't know how to get rid of :
{
"country":{
"_id":{// ============> How to get rid of this _id field?
"_id":"5b56ecab8cba833c28e0e613",
"name":"USA",
"__v":0
}
}
There is something wrong either with my way of using the populate method or how I embed the Address schema in the User, but I am not able to figure it out

I found that the Address was saved in the user document in a way that does not help the populate method to retrieve the country
The JSON with which I was saving the address in the user was like that:
{
// Other fields of the user
address: {
country : {
_id: "5b56ecab8cba833c28e0e613"
}
}
}
But changing it to this form solved the problem:
{
// Other fields of the user
address: {
country : "5b56ecab8cba833c28e0e613"
}
}

Related

How to make mongoDB return the item from inside the array through the id? [duplicate]

This question already has answers here:
Mongoose populate does not populate array
(3 answers)
Closed 3 months ago.
I'm trying to create an order controller where I would like to store in an array other "cart" models by reference, as in "list":
const mongoose = require('mongoose');
const OrderSchema = new mongoose.Schema(
{
list: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Cart',
}],
totalAmount: {
type: Number,
required: true,
},
payment: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
addressNote: {
type: String,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Order", OrderSchema);
I can store the cart ids in the list and ok, but the problem is that when I do a get from order, I would like the list to return what is in the cart and not the ids that I sent
show all order controller:
const Order = require('../../models/Order');
class ShowAllProduct {
async show(req, res) {
try {
const order = await Order.find({}).populate('list').exec();
return res.status(200).json(order);
} catch (err) {
return res.status(500).json(err);
}
}
}
module.exports = new ShowAllProduct();
I tried to do this through the populate method, but without success.
try this way to populate
const order = await Order.find({}).populate({
path:'list',
model:'Cart'
}).lean();
update : if you want to populate Product model from Cart model ,
const order = await Order.find({}).populate({
path:'list',
model:'Cart',
populate:{
path:'product', // field name of product in Cart model
model:'Product'
}
}).lean();
use select:'name image_url' inside populate if you want to select only specific fields from model .
const order = await Order.find({}).populate({
path:'list',
model:'Cart',
populate:{
path:'product', // field name of product in Cart model
model:'Product',
select:'name image_url'
}
}).lean();

MongoDB populate returning null

I am trying to populate my user schema with items but for some reason it does not populate anything in to the user schema. Could someone please take a look. I have 1 user and 1 item belonging to that user within my database but nothing is populating and I keep seeing null.
User Schema
var mongoose = require('mongoose')
var userSchema = mongoose.Schema({
name: {
type: String,
required: true
},
discordID: {
type: String,
required: true
},
discordImage: {
type: String,
required: true
},
items: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Item'
}]
})
const User = module.exports = mongoose.model('User', userSchema)
Item Schema
var mongoose = require("mongoose")
var itemSchema = mongoose.Schema({
name: {
type: String,
required: true
},
purchasedPrice: {
type: Number,
required: true
},
purchasedDate: {
type: String,
required: true
},
author: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User"
}
})
const Item = module.exports = mongoose.model("Item", itemSchema)
Populate Code
app.get("/inventory", async (req, res) => {
try {
await req.user.populate({
path: 'items'
}).execPopulate()
console.log(req.user)
} catch (error) {
console.log(error)
}
res.status(200).render("inventory.ejs", { currentUser: req.user })
})
Objects in the DB:
Item:
User:
Used virtual method on user schema to create association
userSchema.virtual("items", {
ref: "Item",
localField: "_id",
foreignField: "author"
})
Worked fine with original code
I keep seeing null.
and
no its just empty
hints there are no items added to your user. You need to have some ids you can populate.
All populate does is convert an ObjectID into a document. There is no magic that will sync itemSchema.author with userSchema.items.
Hence, it's not enough to add the author to the item. You also need to add the item to the author.
So for example, you could add an item like this:
const item = new Item({author: user._id});
await item.save();
req.user.items.push( item );
await req.user.save();
Now when you log req.user, are there any items there?
Once you see objectIds, then you can go back and add that .populate('items') into the mix and I promise you it'll work.

MongoDB populate() to dynamically load/migrate data not working

I am building an app in which the user adds and deletes objects (Pic) in an array('pics') after registering, but not sure how to dynamically load or populate('pics') to userSchema to automatically render. The user registers on the app with that array originally empty ('pics' = zero), and will create or delete those objects thereafter when logged in.
Following the documentation, I used "await User.find().populate('pics');" to migrate data in index method, but did not work.
Besides, should I include 'pics' key at store method, or userSchema 'pics' should be enough?
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
pics: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Pic"
}
],
});
const picSchema = new mongoose.Schema({
thumbnail: String,
description: String,
dev: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
},
);
const User = mongoose.model('User', userSchema);
const Pic = mongoose.model('Pic', picSchema)
async index(req, res, next) {
const users = await User.find().populate('pics');
res.status(200).json(
devs
);
},
async store(req, res) {
try {
const { name } = req.body;
let user = await User.create({
name,
pics
})
// await user.populate('pics').execPopulate();
res.send({ user })
}
} catch (error) {
res.status(400).send(error);
}
},
I worked a time ago with MongoDB and NodeJS. I think that you have a problem with the definitions. Also, you can read the documentation https://mongoosejs.com/docs/populate.html
You need to define the _id for collections (Schema).
const userSchema = new mongoose.Schema({
_id: new mongoose.Types.ObjectId(),
name: {
type: String,
required: true,
trim: true
},
pics: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Pic"
}
],
});
const picSchema = new mongoose.Schema({
_id: new mongoose.Types.ObjectId(),
thumbnail: String,
description: String,
dev: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
},
);
So, when you create a new User, the _id is completed (you can generate it or it can be generated automatically) and ignore the field pics. When you create a Pic, you need to read the _id of the User and assigned as 'dev', something like:
let pic = new Pic({
thumbnail: '', description: '',
dev: yourUser._id
});
Using this way to create documents, you can use the populate function.

How to find documents inside ref object without an id?

I have two documents in mongodb:
export const Category = mongoose.model('Category', new mongoose.Schema({
name: { type: String },
}));
export const SubCategory = mongoose.model('SubCategory', new mongoose.Schema({
name: { type: String },
category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
}));
How to find All SubCategory that match Category by name?
I have try a lot of ways but I always getting null or error...
var name = '...';
SubCategory.find({ category: { name } });
SubCategory.find({ category: { name } }).populate('category');
You can use aggregation for the same. Please read this documentation https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/
Note:- This answer is based on your collection and data you have entered. this is not perfect but this will help best to find the logic from this answer. :-)
//collection 1 schema
const collection1Schema = new Schema({
user_id: {
type: String,
required: true
},
status: {
type: String
}
});
mongoose.model('Collection1', collection1Schema);
//collection 2 schema
const collection2Schema = new Schema({
user_id: {
type: Schema.Types.ObjectId,
ref: 'user_id'
},
item: {
type: String
}
});
mongoose.model('Collection2', collection2Schema);
//find data from collection2
Collection2.find()
.populate('user_id')
.exec(function(err, foundDocuments) {
if (error) {
console.error(err);
} else {
console.log(foundDocuments);
}
});
For more info:- Mongoose populate

Add Data to MongoDB Models At Different Times

I have a pretty good understanding of mongdoDB with mongoose, but this one aspect of it has been confusing me for a while now. I have a user.js model with a username, password, etc (all the basic user stuff). This data is added when a user registers for an account. But each user also has more data linked to it that IS NOT created or added at the time of registering.
This is my model:
// User Schema
const UserSchema = new Schema({
// PERSONAL USER INFO
username: {
type: String,
index: true
},
email: {
type: String
},
password: {
type: String
},
// INSTAGRAM ACCOUNT INFORMATION
ig_username: {
type: String
},
ig_password: {
type: String
},
story_price: {
type: Number
},
fullpost_price: {
type: Number
},
halfpost_price: {
type: Number
},
leads: [{
title: { type: String }
}]
});
// EXPORTS
const User = module.exports = mongoose.model('user', UserSchema);
All the field except "leads" are created at the time of registering. But I want to fill the Leads field using another form. I've tried the .update(), .save(), $set, $push, and all kinds of methods, but I cannot get it to work.
Most solutions that I have found use var user = new User({...}) to create a new user and then use .save() after adding the additional data. But this seems wrong since the user has already been created and I am just trying to add data to an additional field.
I think I'm just glossing over something basic, but if there is a way to do this I would be glad to hear it. Thanks!
I would create a sub-schema for leads
// Create a sub-schema for leads
const leadsSubSchema = new Schema({
title: {
type: String,
},
});
// Create a schema for user
const UserSchema = new Schema({
username: {
type: String,
index: true
},
// ...
leads: [leadsSubSchema]
});
// EXPORTS
const User = module.exports = mongoose.model('user', UserSchema);
Then for the update
User.update({
_id: user_id,
}, {
$push: {
leads: lead_to_add,
},
});

Resources