Update nested array and populate before that with mongoose - javascript

I would like to add a photo into a country in mongoose. But country is an array and photo too. Here is my user schema :
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
birthDate: {
type: Date,
required: true
},
sex: {
type: String,
required: true
},
countries: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Country',
photos: [
{
base64: {
type: String,
required: true
},
title: String,
description: String
}
]
}
],
admin: {
type: Number,
required: true
}
});
Here is what I got as data into mongoDB :
The problem is that I only got the id of countries. And I would like to use another field of the document country. Populate works well when I want to get data, but how to populate and then use the fields to update with mongoDB?
Moreover, I don't know how to update data into nested array, I tried :
User.findOneAndUpdate(
{
"name": "CHARLAT",
"countries": "5d2d847b06f2f94118a36518"
},
{ $push : { "countries.photos" : {
base64: "bla"
} }}
)
As you can see, I use a hand written id for country... I could do a find query before on country but can we use populate here?
And I got this in Postman :
Thank you in advance for your help !

If the type is ObjectId, it can't have a photos field, since it's just an _id. It is a reference to another collection.
Updated answer after comments :
The best thing to do IMO is to create a Photo model which would have the file path and the country's _id. The User model would only store a list of Photos [_id].
UserSchema :
{
.....
photos : [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Photo'
}],
.....
}
PhotoSchema :
{
country : {
type: mongoose.Schema.Types.ObjectId,
ref: 'Country'
},
path : String
}
Then, query your Users this way, by populating the photos, and inside each photo, populating the countries :
UserModel
.find(conditions)
.populate({
path: 'photos',
model: 'Photo'
populate: {
path: 'country',
model: 'Country'
}
})
.lean() // Faster and lighter for read-only, simply returns an object
So you should get a User object like this :
{
.....
name : "John",
photos : [{
country : {
name : "Country 1",
code : "C1" // or whatever field you have in your Country model
},
path: "path/to/photo1.jpg"
},
{
country : {
name : "Country 2",
code : "C2"
},
path: "path/to/photo2.jpg"
}]
.....
}

Related

CastError: Cast to ObjectId failed for value "{ '$in': [ new ObjectId("6359f421fd4678e2eba3ffee") ] }" (type Object) at path "author" for model "Blog"

I have a blog model:
let blogSchema = new mongoose.Schema({
author: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
title: { type: String, required: true, unique: true },
description: { type: String, required: true, unique: true },
content: { type: String, required: true, unique: true },
likes: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
views: { type: Number, default: 0, required: true },
tags: [],
currentState: { type: String, enum: ['draft', 'published'], required: true, default: 'draft' }}, { timestamps: true });
and a user model which I don't think is necessary to show.
When I try querying for a blog with the author matching a list of userids that the current user is following as such:
let blogs = await Blog.find({ author: { $in: blogIds } })
It gives me the error: CastError: Cast to ObjectId failed for value "{ '$in': [ new ObjectId("6359f421fd4678e2eba3ffee") ] }" (type Object) at path "author" for model "Blog"
How do I get the blogs? I've tried using the $or operator but I would have to loop and it doesn't work anyway. The array values in $in is found correctly as shown in the error, it isn't converting properly though.
The blogids array is [ new ObjectId("6359f421fd4678e2eba3ffee") ]. It is dynamic and is an array of userids that the user follows (OOPS, the name isn't clear)
I think there might be problem in your blogIds array.Try to convert all value inside it with mongoose.Types.ObjectId.
const allIds=blogIds.map(item=>mongoose.Types.ObjectId(item));
Then update your find query.
const blogs = await Blog.find({ author: { $in: allIds } });

How to implement a deep populate using the Mongoose, to properly output a M:N database relation?

I am trying to create a basic social media website, with post having different comments, likes, comments also having likes. If the logged in user is the one that made the comment or post, he could be able to delete the post.
So I have to use the deep populate method of mongoose, but the issue I am having is, when the content of the comment is showing, then the name of the user that made that comment is missing.
Post Schema is as follows
content: {
type: String,
required: true
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
// include the array of ids of all comments in this post schema itself
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment'
}
],
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Like'
}
]
},{
timestamps: true
});
Like Schema is as follows -
const likeSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.ObjectId
},
// this defines the object id of the liked object
likeable: {
type: mongoose.Schema.ObjectId,
require: true,
refPath: 'onModel'
},
// this field is used for defining the type of the liked object since this is a dynamic reference
onModel: {
type: String,
required: true,
enum: ['Post', 'Comment']
}
}, {
timestamps: true
});
User Schema is as follows -
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
name: {
type: String,
required: true
},
avatar: {
type: String
}
}, {
timestamps: true
});
Comment Schema is as follows -
const commentSchema = new mongoose.Schema({
content: {
type: String,
required: true
},
// comment belongs to a user
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
post: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
},
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Like'
}
]
},{
timestamps: true
});
And this is the populate function, on the front end I am trying to display all possible posts with all possible likes and comments, with all the comments also having likes. And obviously the name of the user that made the comment -
let posts = await Post.find({})
.sort('-createdAt')
.populate('user')
.populate({
path: 'comments',
populate: {
path: 'user'
},
populate: {
path: 'likes'
}
}).populate('comments')
.populate('likes');
But in the front end, I am not able to display the User Name that made a particular comment.
Please tell the error.

In MongoDB, when deleting a dataset how do I also remove the associated "child" datasets?

Example: If I delete a user, I want to also remove all of that users associated comments.
const UserSchema = new Schema(
{
username: {
type: String,
unique: true,
},
email: {
type: String,
unique: true,
},
comments: [
{
type: Schema.Types.ObjectId,
ref: "Comment"
}
],
);
Right now I am removing a user with the .findOneAndDelete method.

Mongo nested fields populating issue

var buyerSchema = new Schema({
cart: [{
id: {
type: Schema.Types.ObjectId,
ref: "product"
},
number: Number
}],
personName: { type: String, required: true, trim: true },
image: { type: String, required: false, trim: true },
email: { type: String, required: true, trim: true }
})
How can i populate the Id field
buyerMdl.findByToken(buyer['token']).populate({path: 'cart', populate: {path : 'id', model : 'product'}})
this particular command is not working for me
First of all make sure your findByToken method returns an instance of find so that you can use .populate() in the chain.
The problem is that you're trying to populate a property which is not referenced. So instead of populating card and then ids in it, you should directly populate cart.ids.
This should work:
buyerMdl
.findByToken(buyer['token'])
.populate({
path: 'cart.id',
model: 'product'
});
Your id is inside card array... So you should use with dot notation to populate id
buyerMdl.findByToken(buyer['token']).populate({ path: 'cart.id' })

Upsert: Unable to invalidate a subdocument that has not been added to an array

I have an upsert query in mongoose which was working in 3.8 but, after I've upgraded to 4 I'm getting
Unable to invalidate a subdocument that has not been added to an array
this is my model:
var ActivitySchema = new Schema({
owner:{
type: Schema.Types.ObjectId,
ref: 'User'
},
sequence:{
type:Number,
default: 0
},
items:[
{
posted:{
type:Date,
default:Date.now
},
verb:{
type: String,
enum: [ 'leave','join','support','share','comment', 'upload', 'rate','message','update', 'signup']
},
text:{
type: String,
},
reference: {
objectType:{
type: String,
enum: [ 'document','element','process', 'project', 'user']
},
refObj:{}
}
}]
});
the upsert:
Activity.update({
$and:[
{'owner':ownerId},
{'sequence':bucket}
]},
{
$push:{items:newItem }
},
{
upsert:true
}).execAsync();
and the data is like this:
//newItem
{ verb: 'join',
text: 'Has joined to a team',
reference:
{
refObj: { teamId: '56269fd1e923cc7a7b46dcf8', name: 'test1' },
objectType: 'user'
}
}
ownerId is a mongoId like 56251c01507dc35423694118
and bucket is an integer 0
is there any breacking change that I need to be aware?, I've been looking and I haven't found yet related, any other workaround, solution?
I had encountered the same problem, if it is the same case then make sure all fields type are matched to the mongoose.model('yourModel').
Hopes that helps.

Categories