Delete all occurrences of ObjectId in arrays - node.js

I have the following schema:
var userSchema = new mongoose.Schema({
username: {type: String, required: true},
favouriteItems: [{type: mongoose.Schema.Types.ObjectId, ref: 'Item'}],
userItems: [{type: mongoose.Schema.Types.ObjectId, ref: 'Item'}]
});
var itemSchema = new mongoose.Schema({
name: {type: String, required: true},
price: {type: Number, required: true}
});
mongoose.model('User', userSchema , 'Users');
mongoose.model('Item', itemSchema , 'Items');
When I delete the item, I want to remove its ObjectId from favouriteItems and userItems from all users whose array contains it.
Example:
Initial:
Users:
[
{
_id: "a",
username: "username1",
favouriteItems: ["id1"],
userItems: ["id2", "id3"]
},
{
_id: "b",
username: "username2",
favouriteItems: ["id2"],
userItems: ["id1", "id4"]
},
...
]
Items:
[
{
_id: "id1",
name: "item1",
price: 19
},
{
_id: "id2",
name: "item2",
price: 7
},
...
]
When I remove item with id id1 I want the following result (id1 must be removed from arrays favouriteItems and userItems of all users):
Users:
[
{
_id: "a",
username: "username1",
favouriteItems: [],
userItems: ["id2", "id3"]
},
{
_id: "b",
username: "username2",
favouriteItems: ["id2"],
userItems: ["id4"]
},
...
]
Items:
[
{
_id: "id2",
name: "item2",
price: 7
},
...
]
How do I achieve this using mongoose and node.js?

You should take a look at the post mongoose middleware hooks and specifically the hook on remove:
itemSchema.post('remove', async function(doc) {
// doc is removed ... execute query to remove from favorites using the `doc._id`
});

Related

Mongoose findOne converting the Array type field in object

I have been building a chat application,and I am storing user with a schema
const UserSchema = new mongoose.Schema({
_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
contacts: {
type: ContactSchema,
},
});
and ContactSchema as
const ContactSchema = new Schema({
contactUserId: {
type: String,
required: true,
},
});
the problem is that, when I try to find the user in mongo shell with findOne, It retrieves the user with contacts array:
{
"_id" : "49Ff7aRn4baPuTVFefQLulbMIeE2",
"username" : "john",
"email" : "doe#gmail.com",
"__v" : 0,
"contacts" : [
{
"_id" : ObjectId("5eb07958b0315c6303505f74"),
"contactUserId" : "RHOCbyCtvjQfFzFukxiwS9wV1ly1"
},
{
"_id" : ObjectId("5eb07e4eff338702ba455c8a"),
"contactUserId" : "tGCkdHh55UgkG8AW0Ab6S9guwcF3"
}
]
}
but when I try to use mongoose findOne, It retrieves the user with contacts field as an object:
{ _id: '49Ff7aRn4baPuTVFefQLulbMIeE2',
username: 'john',
email: 'doe#gmail.com',
__v: 0,
contacts:
{ '0':
{ _id: 5eb07958b0315c6303505f74,
contactUserId: 'RHOCbyCtvjQfFzFukxiwS9wV1ly1' },
'1':
{ _id: 5eb07e4eff338702ba455c8a,
contactUserId: 'tGCkdHh55UgkG8AW0Ab6S9guwcF3' },
_id: 5eb086555cbcb03801350d76 } }
Is there any workaround for this ?
That's because of your mongoose UserSchema :
Change contacts: { type: ContactSchema } of type Object to contacts: [ContactSchema] of type array of Objects as like below :
const UserSchema = new mongoose.Schema({
_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
contacts: [ContactSchema],
});
On mongo shell, As you don't have any conversion so it's pretty simple & returns the document from DB as is.
const UserSchema = new mongoose.Schema({
_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
contacts: [ContactSchema]
});
contacts should be mentioned as above instead of
const UserSchema = new mongoose.Schema({
_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
contacts: {
type: ContactSchema,
},
});

How can Mongoose Populate not working with Array of ObjectIds?

I'm trying to populate a mongoose query with an array of objectId field.
In another field with single objectId ref is working fine.
That's my "User" model:
const User = new Schema({
nome: {
type: String,
required: true
},
email: {
type:String,
required: true
}
})
mongoose.model('users',User)
That's my "Pedido" model:
const Schema = mongoose.Schema
const Pedido = new Schema({
id: {
type: String,
required: true
},
cliente: {
type: Schema.Types.ObjectId,
ref: 'clientes',
required: true
},
fotografos: {
type: [Schema.Types.ObjectId],
ref: 'users'
}
})
mongoose.model('pedidos',Pedido)
my router:
router.get('/pedidos',async(req,res)=>{
var query = await Pedido.find().populate('fotografos').populate('cliente').lean().exec()
console.log(query)
res.render("admin/pedidos",{pedidos: query})
})
That's the result in the console.log:
[
{
_id: 5e8e3bd16c57021f682b8e81,
fotografos: [],
cliente: {
_id: 5e8ccceea8a28146d86f4cac,
nome: 'Neymar',
email: 'neymar#ney.com',
__v: 0
},
__v: 0
}
]
fotografos field (array) are returning empty.
clientes field returns populated.
Can anybody help me with this?
You can use this code...
fotografos:[{
type: [Schema.Types.ObjectId],
ref: 'users'
}]
**Then do Populate**

How to add value inside an array of array in mongoose by value find by ID?

I want to add the data inside the order products_id array
I tried to push the array by find it by user id and then add push it inside the products_id but i won't able to add the data.
User.findById(user_id,(err,user)=>{
if(err) throw err;
const lastOrderId = user.order.slice(-1)[0]._id
//console.log(cb.order.slice(-1)[0]._id);
User.update({'order[0]._id': lastOrderId}, {$push: {'order.0.$.products_id': 123}},{safe:true,upsert:true})
/*User.findOneAndUpdate({'_id' : user_id, 'order._id': lastOrderId}
,{$push: [{'order[0].products_id': [123123]}]},{safe:true,upsert:true})*/
})
My User Schema
const userSchema = mongoose.Schema({
_id: mongoose.Types.ObjectId,
user_name: {type:String,require: true},
email: {type:String, require: true},
password: {type:String,require:true},
full_name: {type:String},
order: [{
_id: mongoose.Types.ObjectId,
products_id: [],
date: {
type: Date,
default: Date.now
}
}]
})
After updating i want
const userSchema = mongoose.Schema({
_id: mongoose.Types.ObjectId,
user_name: {type:String,require: true},
email: {type:String, require: true},
password: {type:String,require:true},
full_name: {type:String},
order: [{
_id: mongoose.Types.ObjectId,
products_id: [5d5d7a7ea0c4aaf6212993ec, 5d627a962a5c637e7a0d5d1c, 5d627a49fa24ba7d15451afb],
date: {
type: Date,
default: Date.now
}
}]
})
You can use arrayFilter for this.You can do it like this.
User.update({user_id},{$set: { 'order.$[ord]': lastOrderId },
$push: {'order.$[ord].products.$[prd]':123}
}, {
arrayFilters: [{'_id': user_id}]
})

Populate Virtuals - populate the existing array its referencing .

Is it possible to use mongoose's Populate Virtuals to populate the array of values it is referencing?
User Model
var userSchema = new mongoose.Schema({
auth_key: {type: String},
channels: [{
name: {type: String},
last_access: { type: Date, default: Date.now },
status: {type: String, default: false },
new_messages: {type: Number},
user_channel_group: {type: String}
}]
}, {
toJSON: {
virtuals: true
}
});
userSchema.virtual('channels.details', {
ref: 'channel',
localField: 'channels.name',
foreignField: 'name'
});
var user = mongoose.model('user', userSchema, 'user');
Channel Model
var channelSchema = new mongoose.Schema({
name: {type: String, required: true},
members: [{ type: String, required: true }],
displayName: {type: String},
type: {type: Number},
create_at: {type: Date, default: Date.now}
});
var channel = mongoose.model('channel', channelSchema, 'channel');
My query that I am using I want the virtual to present the channel details from each channel alongside the channels a user is subscribed to. so something like this..
[{
"_id": "588a82ff7fe89686fd2210b0",
"channels": [{
"details": {
"_id": "588a80fd7fe89686fd2210a8",
"name": "channel1",
"members": []
},
"name": "channel1"
}, {
"details": {
"_id": "588a80fd7fe89686fd2210a9",
"name": "channel2",
"members": []
},
"name": "channel2"
}],
"id": "588a82ff7fe89686fd2210b0"
}
...
]
My Query for this is ..
user.find({}).populate('channels.details').exec()

How to make .populate exclude null values?

Is there a way to exclude lessons.lesson_id that are equal to null? I have the following from previous answers, but it's still giving lessons.lesson_id that are null
module.exports.getClasses = function(id, callback){
Class.findById(id)
.populate(
{path: 'lessons.lesson_id',
model: 'Lesson', $ne: null}
).exec(callback)
}
var classSchema = new Schema({
title: { type: String, required: true },
lessons: [{
_id: false,
lesson_id: {type: mongoose.Schema.Types.ObjectId, ref: 'Lesson'}
}],
});
I'm trying to prevent the lesson_id with null from showing up
{ _id: 58090,
title: 'vcvc',
__v: 0,
lessons: [ { lesson_id: null }, { lesson_id: [Object] } ] }
So your ClassSchema is a touch off, I think you may find this will work better based on your requirements:
var classSchema = new Schema({
title: { type: String, required: true },
lessons: [{type: mongoose.Schema.Types.ObjectId, ref: 'Lesson'}],
});

Resources