Edit nested values by relational _id in mongoose - node.js

Hello I have relational _ids in an array. The object content is in other collection. I can only view Object("_id") in my array.
I want to edit object of those _ids. How can I edit by using relational _ids ??
I have data response like this
{
"admins": {
"users": [
"5d089739d8aae228d7f10c1e" //<------ edit this id object
],
"email": "jertacomlu#desoz.com",
"password": "$2a$10$C/DsmoHK57vIUt7g4wRsYulHLigmc1wGLObwu2/qkFkSeYp28bAOy",
},
"_id": "5d089264d8aae228d7f10c1d",
"companyName":"Company 1",
"__v": 0
}
So this id is stored in other collection name Userr.
the object is like this:-
[ {
"_id": "5d089739d8aae228d7f10c1e",
"email": "jertacomlu#desoz.com",
"password": "$2a$10$0Slx3yFeb7UD0qep.TWSI.JpQGl0CzlGhNJ162JtA5Uvt6osyrIl.",
"firstName": "Sima",
"lastName": "Cezo",
"phoneNumber": "8877123456",
"__v": 0
}
]
I want to edit these fields. How can I do by using relation _id ?
EDIT:-
my parent controller
var admin = new Admin();
admin.companyName = req.body.companyName;
admin.admins = {
email : req.body.email,
password: req.body.password,
role : "admin",
verified :"false",
active: "OFF",
users : []
};

admin.find({id:"5d089264d8aae228d7f10c1d"}).populate("users").then(data=>{
//update the fields which you would find in the data object
data.save()
//your data would be changed.
})

You must create a method at model User , example to edit email :
User.edit=async function (id,newEmail){
let user = await User.findOne({_id:id}).exec();
user.email=newEmail;
await user.save();
}
In Admin ,
...
let admin = await Admin.findOne({_id:id}).exec();
await User.edit(admin.users[0])
...

Related

Document is inserted twice into MongoDB when using Mongoose create method

I am having below schema in my API which gets details of username and the products he added to the cart.
const mongoose = require('mongoose');
mongoose.connect('mongodb connection').then(()=>{
console.log('DB connection is successfull');});
const AutoIncrement = require('mongoose-sequence')(mongoose);
const cartSchema = new mongoose.Schema({
cartId : {
type : Number
},
username : {
type : String
},
productsInCart : [{
productId : {type : Number,required : true},
productName : {type:String},
quantity : {type:Number}
}],
statusOfCart : {
type : String,
default : 'Open'
}},{ timestamps: true });
cartSchema.plugin(AutoIncrement,{id : 'cart_seq',inc_field : 'cartId'});
let cartModel = mongoose.model('carts',cartSchema);
module.exports = cartModel;
As you can see in the above code I am also using the mongoose-sequence to make cartId as a auto-incremented field.
Now, I have a POST request which gets the below JSON in request body and adds it to the cart collection in the MongoDB using the create method.
{
"username":"admin",
"productsInCart":
[
{
"productId":1,
"productName":"Watch",
"quantity":4
},
{
"productId":2,
"productName":"Phone",
"quantity":5
}
]
}
The code inside the Route Handler for the POST request in Express API would look something like this
let ctMod = new cartModel();
ctMod.username = req.body.username;
ctMod.productsInCart = req.body.productsInCart;
let insCartData = await cartModel.create(ctMod,{new:true});
if(insCartData.length > 0)
{
return res.status(200).json({
message : `New items got inserted into the cart with the ID : ${insCartData.cartId}`,
data : insCartData
});
}
The above code inserts two entries into the collection like below instead of one
{
"statusOfCart": "Open",
"productsInCart": [],
"createdAt": "2021-01-04T15:25:35.188Z",
"updatedAt": "2021-01-04T15:25:35.188Z",
"cartId": 13,
"__v": 0
},
{
"statusOfCart": "Open",
"productsInCart": [
{
"_id": "5ff332a891aa170b60a21ea9",
"productId": 1,
"productName": "Watch",
"quantity": 4
},
{
"_id": "5ff332a891aa170b60a21eaa",
"productId": 2,
"productName": "Phone",
"quantity": 5
}
],
"username": "admin",
"createdAt": "2021-01-04T15:25:35.210Z",
"updatedAt": "2021-01-04T15:25:35.210Z",
"cartId": 14,
"__v": 0
}
can you help me understand why there is duplicate entries in my db?
I'm not sure why you are using cartModel.create(ctMod,{new:true}); inorder to create a new entry to your collection.
You can simply do like this :
let ctMod = new cartModel();
ctMod.username = req.body.username;
ctMod.productsInCart = req.body.productsInCart;
try{
let insCartData = await cartModel.save();
return res.status(200).json({
error:false,
message : `New items got inserted into the cart with the ID : ${insCartData.cartId}`,
data : insCartData
});
}
catch(err){
console.error("error inserting data", err);
return res.status(500).json({error:true, message:"Something went wrong :("}).
}
UPDATE :
Reason for the duplicate entry is that you are passing the {new:true} flag in the create API. It's used to return the updated document in the findOneAndUpdate method. But in create/save, the mongoose return the data by default. Hence the flag is not needed.If you omit the flag, duplicate entries can be prevented.
Also, as you are using the create method to save the new entry, you need not create an instance of the cartModel. ie.,
let ctMod = new cartModel();
can be just
let ctMod = {}
Hope it helps!

Mongoose query to check array contains element or not in mongoose query

i have records like this..
{
"photo": "default.jpg",
"roles": [
{
"_id": "5f44d77be830263684eb7914",
"name": "Test",
"__v": 0
}
],
"_id": "5f44d2f4ff04993b40684bf9",
"name": "Test User",
"email": "test#gmail.com",
"id": "5f44d2f4ff04993b40684bf9"
}
i want to weather the role user trying to delete is in use or not. for this i have write a query but it always return an empty array.
const check = await User.find({roles: {$elemMatch: {_id: req.params.id}}});
these are the queries i checked in compass but it always an array
{"roles._id":"5f44d77be830263684eb7914"}
{roles: $elemMatch: {_id: "5f44d77be830263684eb7914"}}
my User document hass roles field something like this.
roles:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"Roles",
validate: {
validator: async function(v) {
return await Roles.findById(v, (err, rec) => rec !== null)
},
message: 'Invalid Object ID'
},
required:true
}
],
IS there any way to enforce integrity constraint like if user tries to delete records which have dependencies on other records then we should not allow user to delete this record.

Multiple conditions in updateOne query in mongodb

Document in mongodb collection 'users' is
{
"$oid": "5e612272bcb362513824ff9b",
"name": "abcd",
"email": "test#test.com",
"cart": {
"items": [{
"productId": {
"$oid": "5e614367cae25319c4388288"
},
"quantity": {
"$numberInt": "1"
}
}]
}
}
For a particular users._id and a productId in cart.items, I need to increase the quantity by 1
My nodejs code is
IncrCartItem(prodId){
const db=getDb()
return db
.collection('users').
updateOne({_id: new mongodb.ObjectId(this._id),'this.cart.items.productId': new mongodb.ObjectId(prodId)},{$inc : {'this.cart.items.quantity':1}})
}
Is the query right for checking multiple conditions in updateOne()??
You're kinda there, to "and" them all together you just keep appending them, however the field is wrong and you need to use the positional operator ($) - https://docs.mongodb.com/manual/reference/operator/update/positional/
const filter = {
_id: new mongodb.ObjectId(this._id),
'cart.items.productId': new mongodb.ObjectId(prodId)
};
const update = {
$inc : { 'this.cart.items.$.quantity': 1 }
};
IncrCartItem(prodId){
const db=getDb()
return db
.collection('users').
updateOne(filter,update)
}

How to populate updated document by id in schema array

I am trying to learn and implement few operations which are newer for me. I have a child schema details which I am pushing in a parent schema array. Everything is going fine. But when it comes to front-end, concern about few things.
As per someone's advice ,I came to know we must store _id to another schema . And if we update details of that _id, it will get reflected in every schema docs where it has been stored.
Now I am login through parent schema and I want to see the entire details of those array _id as I need to show lists in front-end. Right now I can only see ids. I want to populate array of entire object of those ids.
I can populate data but I need to use a different API Url to show list. I do not want that . I know if I change ObjectId to Mixed, I can see whole object. But problem is that it will not show updated data. So I am pushing by ObjectId users:[ {type: mongoose.Schema.Types.ObjectId, ref: 'Userr'}]
So how will I populated updated users aray data on my main schema array without creating new route api ??
Child schema:-
{
"_id": "5d034653ff1e426fb0e3fca1",
"firstName": "xyz",
"lastName": "fg",
"__v": 0
}
Main schema response details :-
{
"admins": {
"users": [
"5d034653ff1e426fb0e3fca1" //<========= what i am getting
],
"email": "1cf1eede89#himail.online",
"password": "$2a$10$vHyGxX9P.t0/ybKcmIzkc.ZCX18oHaVnvTgJIWA2gTNzJ3TCdXS4a",
},
"_id": "5d0339d5b4b28b6ddff06802",
"companyID": "497399",
"__v": 0
}
I want to show result like this :
{
"admins": {
"users": [
"5d034653ff1e426fb0e3fca1",
"firstName" : "xyz",
"lastName" :"fg"
],
"email": "1cf1eede89#himail.online",
"password": "$2a$10$vHyGxX9P.t0/ybKcmIzkc.ZCX18oHaVnvTgJIWA2gTNzJ3TCdXS4a",
},
"_id": "5d0339d5b4b28b6ddff06802",
"companyID": "497399",
"__v": 0
}
Function for registering user :-
if(req.userData.role2 === 'admin') {
console.log("saving successful");
res.send(doc);
Admin.findOneAndUpdate({ _id: req.userData.userId }, { $push: { 'admins.users': userr._id } }, { new: true })
.populate('admins.users')
.exec(function(error, res){
if (error) {
console.log(error);
}else {
console.log(res.admins.users+ "populated")
}
});
}
This is showing me list of populate data but how can I show it in array object
I need to show the updated object of child schema. So that I can use in front-end for listing whatever details I want

How to get information from all collection, but get only item of array

I'm using MongoDB with NodeJS, and I keep my data in a collection called "posts", in this way
{
"_id": "5ca0ff61f247dc29b8331af9",
"tipo": "First Mongo Post",
"user": {
"_id": "5ca01d2c56a2d9165c848f4f",
"nombre": "User1",
"email": "luis#gmail.com",
"permission": "Administrador",
"__v": 0
},
"rates": [
{
"user": "5ca01d2c56a2d9165c848f4f",
"votation": 1
},
{
"user": "5ca021b03904f70cf823b6e6",
"votation": -1
}
],
"__v": 0
}
I would like to think that the way that I save my data its correctly, whatever, I want to get all the information from my collection called "posts", but the array called rates, I only want to get the object that the user its the same like the user that make the call to the get method.
For example, If I call my get method, and I send the user ID (5ca01d2c56a2d9165c848f4f), I want to return all posts collection but in the the rates array of each one I only want to have the object that has the same ID compared by the ID that I sent in the get method, for example:
{
"_id": "5ca0ff61f247dc29b8331af9",
"tipo": "First Mongo Post",
"user": {
"_id": "5ca01d2c56a2d9165c848f4f",
"nombre": "User1",
"email": "luis#gmail.com",
"permission": "Administrador",
"__v": 0
},
"rates": [
{
"user": "5ca01d2c56a2d9165c848f4f",
"votation": 1
}
],
"__v": 0
}
To be honest, I don't know how can I do it, so i hope that you can help me or explain me how can I do it, please.
Regards, I'm new using this technologies
You can store Rate and Post objects separately, so you can create a new collection called rates to keep Rates separately from Posts collection. In the Rate collection you can store the postId, userId and votation value
const mongoose = require('mongoose');
const RateSchema = new mongoose.Schema({
userId: {
type: String
},
postId: {
type: String
},
votation: {
type: Number,
}
);
module.exports = mongoose.model('Rate', RateSchema);
After that you can create a function to get the rates that is related to userId and postId like
const Rate = require('../models/Rate');
function getRatesByUserIdandPostId(userId, postId) {
return Rate.find({userId, postId});
};
This way you don't need to search in a for loop for which rate is relate to that user, function will do it for you. Also it is faster because you don't get all the rates that is related to one specific post.

Resources