User schema looks something like this
addressId: [{ type: mongoose.Schema.Types.ObjectId, ref: 'address' }],
mongoose.model('user', userSchema);
Address model
mongoose.model('address', postalAddressSchema);
I am trying to do this:
const createdUser = await mongoose.models.user.create(user);
return { success: true, user: createdUser.populate('addressId') };
I am trying to populate address in user creation. It returns null
You may try to find, populate and exec after creating the user. Here is a working example
const theMongoose = await mongoose.connect(mongoServerUri);
const accountModel = theMongoose.model(
'Account',
new Schema({
_id: Schema.Types.ObjectId,
name: String
})
);
const activityModel = theMongoose.model(
'Activity',
new Schema({
account: { type: Schema.Types.ObjectId, ref: 'Account' },
date: Date,
desc: String
})
);
const account = await accountModel.create({ name: "Test User", _id: mongoose.Types.ObjectId.createFromTime(new Date().getTime()/1000) });
await activityModel.create({ date: new Date(), desc: "test", account: account.id });
// find, populate, & exec
const res = await activityModel.find({ desc: "test" }).populate("account").exec()
console.log(res);
And the output is
[
{
_id: new ObjectId("62da50ec77c026e2aad5577b"),
account: {
_id: new ObjectId("62da50ea0000000000000000"),
name: 'Test User',
__v: 0
},
date: 2022-07-22T07:25:32.119Z,
desc: 'test',
__v: 0
}
]
Related
I have the following schemas:
"use strict";
const mongoose = require('mongoose'),
Schema = mongoose.Schema,
autopopulate = require('mongoose-autopopulate');
const child = new Schema({
userUuid: {
type: String,
required: true
},
timeStamp: {
type: Date,
default: new Date()
}
}, {toJSON: {virtuals: true}});
child.virtual('user', {
ref: 'users',
localField: 'userUuid',
foreignField: 'uuid',
autopopulate: true
});
const parentList= new Schema({
//some properties
children: [child]
});
parentList.plugin(autopopulate);
module.exports = parentList;
I need the Children's list to extract a full object - but it does not work.
When I put a single user not as a child then it works well:
const try= new Schema({
//some properties
userUuid: {
type: String,
required: true
}
}, {toJSON: {virtuals: true}});
try.virtual('user', {
ref: 'users',
localField: 'userUuid',
foreignField: 'uuid',
autopopulate: true
});
try.plugin(autopopulate);
module.exports = try;
This leads me to the conclusion that the problem is when the virtual is within the child schema
What am I missing?
Here's the full code of my attempt to reproduce yours :
const
{ randomUUID } = require('node:crypto'),
{ MongoMemoryServer } = require('mongodb-memory-server'),
mongoose = require('mongoose'),
{ Schema } = mongoose,
autopopulate = require('mongoose-autopopulate');
(async () => {
const
dbServer = await MongoMemoryServer.create(),
dbClient = mongoose.createConnection(dbServer.getUri());
dbClient.on('disconnected', () => dbServer.stop());
await new Promise(resolve => dbClient.once('connected', () => resolve()));
try {
const trySchema = new Schema({
//some properties
userUuid: {
type: String,
required: true
}
}, { toJSON: { virtuals: true } });
trySchema.virtual('user', {
ref: 'users',
localField: 'userUuid',
foreignField: 'uuid',
autopopulate: true
});
trySchema.plugin(autopopulate);
const childSchema = new Schema({
userUuid: {
type: String,
required: true
},
timeStamp: {
type: Date,
default: new Date()
}
}, { toJSON: { virtuals: true } });
childSchema.virtual('user', {
ref: 'users',
localField: 'userUuid',
foreignField: 'uuid',
autopopulate: true
});
childSchema.plugin(autopopulate);
const parentListSchema = new Schema({
//some properties
children: [childSchema]
});
parentListSchema.plugin(autopopulate);
const userSchema = new Schema({
uuid: {
type: String,
required: true
}
});
const
Try = dbClient.model('try', trySchema),
Child = dbClient.model('child', childSchema),
ParentList = dbClient.model('parentList', parentListSchema),
User = dbClient.model('users', userSchema);
const userUuid = randomUUID();
await new User({ uuid: userUuid }).save();
await new Try({ userUuid }).save();
const child = await new Child({ userUuid }).save();
await new ParentList({ children: [child] }).save();
console.log('User:', (await User.findOne().exec()).toJSON());
console.log('Try:', (await Try.findOne().exec()).toJSON());
console.log('Child:', (await Child.findOne().exec()).toJSON());
console.log('ParentList:', (await ParentList.findOne().exec()).toJSON());
}
catch(error){
console.error(error);
}
dbClient.close();
})();
Which outputs :
User: {
_id: new ObjectId("62c6e7bcef50638fe0097866"),
uuid: 'bb5af665-759a-4da0-880d-8a54ce42be4c',
__v: 0
}
Try: {
_id: new ObjectId("62c6e7bcef50638fe0097868"),
userUuid: 'bb5af665-759a-4da0-880d-8a54ce42be4c',
__v: 0,
user: [
{
_id: new ObjectId("62c6e7bcef50638fe0097866"),
uuid: 'bb5af665-759a-4da0-880d-8a54ce42be4c',
__v: 0
}
],
id: '62c6e7bcef50638fe0097868'
}
Child: {
_id: new ObjectId("62c6e7bcef50638fe009786b"),
userUuid: 'bb5af665-759a-4da0-880d-8a54ce42be4c',
timeStamp: 2022-07-07T14:03:40.902Z,
__v: 0,
user: [
{
_id: new ObjectId("62c6e7bcef50638fe0097866"),
uuid: 'bb5af665-759a-4da0-880d-8a54ce42be4c',
__v: 0
}
],
id: '62c6e7bcef50638fe009786b'
}
ParentList: {
_id: new ObjectId("62c6e7bcef50638fe009786e"),
children: [
{
userUuid: 'bb5af665-759a-4da0-880d-8a54ce42be4c',
timeStamp: 2022-07-07T14:03:40.902Z,
_id: new ObjectId("62c6e7bcef50638fe009786b"),
__v: 0,
id: '62c6e7bcef50638fe009786b'
}
],
__v: 0
}
I'm not sure what you meant about [needing] the Children's list to extract a full object.
If you were talking about Child.user then you were only missing child.plugin(autopopulate);.
If you were talking about ParentList.children then it worked out of the box for me.
I have a model defined as so:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const feedbackSchema = new Schema({
Name: {
type: String,
required: true,
},
Email: {
type: String,
required: true,
},
Project: {
type: String,
required: true,
},
Wonder: {
type: String,
required: true,
},
Share: {
type: String,
required: true,
},
Delight: {
type: String,
required: true,
},
Suggestions: {
type: String,
required: true,
},
Rating: {
type: String,
required: true,
},
dateCreated: {
type: Date,
default: Date.now(),
},
user: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
const UserSchema = new Schema({
googleId: {
type: String
},
displayName: {
type: String
},
firstName: {
type: String
},
lastName: {
type: String
},
image: {
type: String
},
createdAt: {
type: Date,
default: Date.now(),
},
feedback: [feedbackSchema],
})
module.exports = mongoose.model("User", UserSchema);
An example document:
{
_id: ObjectId('60b9dc728a516a4669b40dbc'),
createdAt: ISODate('2021-06-04T07:42:01.992Z'),
googleId: '2342987239823908423492837',
displayName: 'User Name',
firstName: 'User',
lastName: 'Name',
image: 'https://lh3.googleusercontent.com/a-/89wf323wefiuhh3f9hwerfiu23f29h34f',
feedback: [
{
dateCreated: ISODate('2021-06-04T07:42:01.988Z'),
_id: ObjectId('60b9dc858a516a4669b40dbd'),
Name: 'Joe Bloggs',
Email: 'joe#bloggs.com',
Project: 'Some Project',
Suggestions: 'Here are some suggestions',
Rating: '10'
},
{
dateCreated: ISODate('2021-06-04T08:06:44.625Z'),
_id: ObjectId('60b9df29641ab05db7aa2264'),
Name: 'Mr Bungle',
Email: 'mr#bungle',
Project: 'The Bungle Project',
Suggestions: 'Wharghable',
Rating: '8'
},
{
dateCreated: ISODate('2021-06-04T08:08:30.958Z'),
_id: ObjectId('60b9df917e85eb6066049eed'),
Name: 'Mike Patton',
Email: 'mike#patton.com',
Project: 'No More Faith',
Suggestions: 'Find the faith',
Rating: '10'
},
],
__v: 0
}
I have two routes defined, the first one is called when the user clicked a button on a feedback item on the UI which takes the user to a "are you sure you want to delete this record"-type page displaying some of the information from the selected feedback record.
A second route which, when the user clicks 'confirm' the subrecord is deleted from the document.
The problem I'm having is I can't seem to pull the feedback from the user in order to select the document by id, here's what I have so far for the confirmation route:
router.get('/delete', ensureAuth, async (req, res) => {
try {
var url = require('url');
var url_parts = url.parse(req.url, true);
var feedbackId = url_parts.query.id;
const allFeedback = await User.feedback;
const feedbackToDelete = await allFeedback.find({ _id: feedbackId });
console.log(feedbackToDelete);
res.render('delete', {
imgSrc: user.image,
displayName: user.firstName,
feedbackToDelete
});
} catch (error) {
console.log(error);
}
})
Help much appreciated
Update
You should be able to do just this:
const feedbackToDelete = await User.feedback.find({ _id: feedbackId });
Or if feedbackId is just a string, which is appears to be, you may have to do something like:
// Create an actual _id object
// That is why in your sample doc you see ObjectId('foobarbaz')
const feedbackId = new mongoose.Types.ObjectId(url_parts.query.id);
const feedbackToDelete = await User.feedback.find({ _id: feedbackId });
Original
Shouldn't this:
const allFeedback = await User.feedback; (a field)
be this:
const allFeedback = await User.feedback(); (a method/function)
?
I am pretty new at mongoose and nodejs so I was doing my project referring to mongoose document. I want to remove a particular subdocument in the comment array by identifing the subdocument with its id. I trried doing it using "pull" as well as "id" method as shown in the image. I couldn't find any mistake in my syntax as well but still it is working.
This is sample document from my db:
{
comments: [
{
replyComment: [],
_id: 601a673735644c83e0aa1be3,
username: 'xyz123#gmail.com',
email: 'xyz123#gmail.com',
comment: 'test123'
},
{
replyComment: [],
_id: 601a6c94d1653c618c75ceae,
username: 'xyz123#gmail.com',
email: 'xyz123#gmail.com',
comment: 'reply test'
},
{
replyComment: [],
_id: 601eb7ba7233015d7090c6bf,
username: 'xyz123#gmail.com',
email: 'xyz123#gmail.com',
comment: 'test comment'
},
{
replyComment: [],
_id: 601ec090f5f22d75b41bec7b,
username: 'xyz123#gmail.com',
email: 'xyz123#gmail.com',
comment: 'test comment123'
}
],
_id: 601a3b8038b13e70405cf9ea,
title: 'latest test',
snippet: 'latest test snippet',
body: 'latest test body',
createdAt: 2021-02-03T05:58:24.123Z,
updatedAt: 2021-02-07T06:56:53.902Z,
__v: 15
}
By doing this test findById("601a3b8038b13e70405cf9ea") and console.log(result)
My topicSchema file:
const mongoose = require('mongoose');
const Schema =mongoose.Schema;
const topicSchema = new Schema({
title: {
type: String,
required: true
},
snippet: {
type: String,
required: true
},
body: {
type: String,
required: true
},
comments: {
type: Array,
required: false
}
}, {timestamps: true},{ versionKey: false });
const Topic = mongoose.model('Topic', topicSchema);
module.exports = Topic;
My commentSchema file:
const mongoose = require('mongoose');
const Schema =mongoose.Schema;
const comSchema = new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
comment: {
type: String,
required: true
},
replyComment: {
type: Array,
required: false
},
}, {timestamps: true},{versionKey: false});
const Comm = mongoose.model('comm', comSchema);
module.exports = Comm;
You have not defined topic and don't using topic = result, with , because it's not necessary
so doing like this :
result.comments.id(commId).remove();
result.save()
if you want to using topic just try
let topic = result;
topic.comments.id(commId).remove();
topic.save()
for this document you can using update and $pull like this:
Topic.updateOne(
{
_id: req.params.id,
},
{
$pull: {
"comments" : { _id: req.params.id1 }
},
},
).then((res)=>{
console.log(res)
}).catch(err=>{
console.log(err)
});
if you can use async/await just try
app.delete('/topic/:id/comments/:id1',async(req,res)=>{
let result = await Topic.findById(req.params.id);
result.comments.id(req.params.id1).remove();
let finalResult = await result.save()
console.log(finalResult)
})
and with .then() .catch approach:
Topic.findById(res.params.id).then(result=>{
let topic = result;
topic.comments.id(res.params.id1).remove();
topic.save().then(result=>{
console.log(result)
}).catch(err=>console.log(err))
}
).catch(err=>{
console.log(err)
});
NOTE: update the mongodb to 4.4 and uninstall mongoose module and install again
I'm doing some tests with MongoDB and NodeJS for a new project.
Searching the documentation I found that it is possible to make references to other collections and bring this data to JSON.
It was then that I decided to perform the following test:
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const userSchema = new Schema({
name: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unique: true,
},
posts: [{
type: Schema.Types.ObjectId,
ref: 'Post'
}]
})
const userModel = mongoose.model('User', userSchema)
const postSchema = new Schema({
title: {
type: String
},
content: {
type: String
},
author: {
type: Schema.Types.ObjectId,
ref: 'User'
}
})
const postModel = mongoose.model('Post', postSchema)
const saveUser = new userModel({
name: 'user',
email: 'user#email.com'
})
saveUser.save()
const savePost = new postModel({
title: 'Lorem',
content: 'Lorem Ipsum',
author: saveUser._id
})
savePost.save()
postModel.find()
.populate('User')
.exec((err, post) => {
console.log(post)
})
However the return of JSON is:
{
_id: 5edd0c24a4f42b0e126f4b15,
title: 'Lorem',
content: 'Lorem Ipsum',
author: 5edd0c24a4f42b0e126f4b14,
__v: 0
}
When should it be:
{
_id: 5edd0c24a4f42b0e126f4b15,
title: 'Lorem',
content: 'Lorem Ipsum',
author: {
_id: 5edd0c24a4f42b0e126f4b14,
name: user,
email: user#email.com
},
__v: 0
}
Does anyone know any solution to this problem where I can insert for all my new Schemas?
Regarding populate you should provide the field name provided in postSchema. So should replace .populate('User') with .populate('author').
Since the post requires the author _id you should save the post only after the author is successfully saved
const saveUser = new userModel({
name: "user",
email: "user#email.com",
});
saveUser.save((err, data) => {
if (err) console.log(err);
else {
const savePost = new postModel({
title: "Lorem",
content: "Lorem Ipsum",
author: saveUser._id,
});
savePost.save();
}
});
I want to populate my property (subCategories) but it's return empty although there are results in my database. Did I have miss something? I followed the populate method in mongoose:
const Document = mongoose.model('Document', new mongoose.Schema({
name: { type: String },
description: { type: String },
subCategory: { type: mongoose.Schema.Types.ObjectId }
}));
const Category = mongoose.model('Category', new mongoose.Schema({
name: { type: String },
subCategories: [
{
name: { type: String }
}
]
})
);
var cat1 = await new Category({ name: 'cat1', subCategories: [{ name: 'sub-1-cat-1' }, { name: 'sub-1-cat-2' } ]}).save();
var cat2 = await new Category({ name: 'cat2', subCategories: [{ name: 'sub-2-cat-1' }, { name: 'sub-2-cat-2' } ]}).save();
await new Document({ name: 'doc1', description: 'blabla', subCategory: cat2.subCategories[1] }).save();
const results = Document.find({}).populate('subCategory');
// results[0].subCategory is empty?! why?
The subcategory must be a mongoose model in order to be populated, currently the subCategory that you're trying to populate is just an array item for Category model so I would refactor the code you've posted above to this:
const SubCategory = mongoose.model('SubCategory', new mongoose.Schema({
name: { type: String }
}));
const Document = mongoose.model('Document', new mongoose.Schema({
name: { type: String },
description: { type: String },
subCategory: { type: mongoose.Schema.Types.ObjectId, ref: "SubCategory" }
}));
const Category = mongoose.model('Category', new mongoose.Schema({
name: { type: String },
subCategories: [
{ type: mongoose.Schema.Types.ObjectId, ref: "SubCategory" }
]
})
);
var sub1Cat1 = await new SubCategory({ name: 'sub-1-cat-1' }).save();
var sub1Cat2 = await new SubCategory({ name: 'sub-1-cat-2' }).save();
var sub2Cat1 = await new SubCategory({ name: 'sub-2-cat-1' }).save();
var sub2Cat2 = await new SubCategory({ name: 'sub-2-cat-2' }).save();
var cat1 = await new Category({ name: 'cat1', subCategories: [sub1Cat1, sub1Cat2 ] }).save();
var cat2 = await new Category({ name: 'cat2', subCategories: [sub2Cat1, sub2Cat2 ] }).save();
await new Document({ name: 'doc1', description: 'blabla', subCategory: cat2.subCategories[1] }).save();
const results = Document.find({}).populate('subCategory');
// results[0].subCategory is not empty!