remove item from nested array using $pull - node.js

Hey I have one problem with remove nested array from my database, I would like use findOneAndUpdate and $pull. My point is to remove item from reply array. I try find comments item by _id and remove this reply item, but this not working. Please look on my code below.
my schema
var productSchema = new Schema({
description: [{
type: String,
require: true,
}],
comments: [{
body: {
type: String,
trim: true,
},
author: {
type: String,
},
date: {
type: Date,
},
reply: [{
body: {
type: String,
trim: true,
},
author: {
type: String,
}, date: {
type: Date,
}
}]
}]
});
api
router.put('/dashboard/admin/komentarz/odpowiedz/usun/', function(req, res) {
var currentCourse = req.body._id; // main item id
var deleteReply = req.body.reply; // reply item id
var commentId = req.body.commentId // comments item id
Product.findOneAndUpdate({ _id: currentCourse }, { $pull: { reply: req.body.reply }}, function(err, product){
//some code
})

Take ref from Mongoose, pull from subdocument
Product.findOneAndUpdate({
_id: currentCourse,
// make sure sub document have a unique field let take _id
"comments._id" : 'commentId'
},
{
$pull: {
"comments.$.reply": {
_id:'replyId'
}
}
},
{
upsert:false,
new:true
}, function(err, product){
//some code
})

Related

Pushing items to array in mongoose

i am trying to create items to specific id of collection using nodejs and mongoose but i am getting CastError which i shared below picture. So goal is, I binded items id in collection schema because collection has many items and when i create items to the specific id of collection i want to push them to items array in the collection schema.
ERROR
ITEMS ROUTE
itemRouter.post("/:collectionId", JWTAuthMiddleware, async (req, res, next) => {
const {name} = req.body
if (req.params.collectionId.length !== 24)
return next(createHttpError(400, "Invalid ID"));
const collection = await CollectionModal.findByIdAndUpdate(
req.params.collectionId,
{
$push : { items: { ...req.body, owner: req.user._id, id: uuidv4() } },
},
{ new: true }
);
if (!collection)
return next(
createHttpError(
400,
`The id ${req.params.collectionId} does not match any collections`
)
);
res.send(collection);
});
Collection schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const collectionSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
image: { type: String },
additionalCustomFields: {
fieldNumber: { type: Number },
fieldName: { type: String },
fieldType: { type: String },
fieldChecked: { type: Boolean },
fieldDate: { type: Date },
},
owner: { type: Schema.Types.ObjectId, ref: "User" },
items: [{ type: Schema.Types.ObjectId, ref: "Item" }],
},
{ timestamps: true }
);
// collectionSchema.index({ "$**": "text" });
export default model("Collection", collectionSchema);
ITEM schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const itemSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
image: { type: String },
comments: [
{
user: { type: Schema.Types.ObjectId, ref: "User", required: true },
text: { type: String },
},
],
tags: { type: String },
owner: { type: Schema.Types.ObjectId, ref: "User" },
likes: [{ type: Schema.Types.ObjectId, ref: "User" }],
collections: { type: Schema.Types.ObjectId, ref: "Collection" },
},
{ timestamps: true }
);
itemSchema.index({ "$**": "text" });
export default model("Item", itemSchema);
Are you sure that using referenced documents is the correct way to go here? Mongoose is complaining because you are trying to push whole objects to the "items" array, instead of ObjectIds of referenced documents.
You have 2 choices here:
1. use embedded documents
This way you can easily store objects directly to the items array, which does not allow you to store the Items in a seperate collection
2. first create Item documents, then push the reference to items array
In this case you have to first create the items in Item collection. Afterwards you can map the result to only ObjectIds and push these to items array of your collection document.

how to insert into deeply nested element API nodejs mongoose

I have 4 nested documents as follow:
//Nested sub document subControl
const SubControlSchema = new Schema({
subControlNo: {
type: String
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
//Nested sub document control
const ControlSubSchema = new Schema({
mainControl: {
type: String
},
subControls: [SubControlSchema],
controlDescription: {
type: String,
trim: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
//Nested sub document domain
const DomainSubSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
domainNo: {
type: String,
trim: true
},
domainName: {
type: String,
trim: true
},
domainDescription: {
type: String,
trim: true
},
controls: [ControlSubSchema],
updated: Date,
created: {
type: Date,
default: Date.now
}
});
// framework Schema
const FrameworkSchema = new Schema({
name: {
type: String,
trim: true
},
description: {
type: String,
trim: true
},
regulator: {
type: Schema.Types.ObjectId,
ref: 'Regulator',
default: null
},
client: {
type: Schema.Types.ObjectId,
ref: 'Client',
default: null
},
domains: [DomainSubSchema],
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('Framework', FrameworkSchema);
I'm trying to post a control under the domain which is inside the framework, here's what I have been trying to do:
//Add new control under a specific domain and framework
router.post('/add/:frameworkId/:domainId', auth, async (req, res) => {
try {
const control = req.body.controls; //take the request from the body
const query = { _id: req.params.frameworkId, _id: req.params.domainId };//pushing into the framework model by taking the ID from URL
await Framework.updateOne(query, { $push: { domains: control } }).exec(); //push the query into the framework model
res.status(200).json({
success: true,
controls: control
});
} catch (error) {
res.status(400).json({
// error: 'Your request could not be processed. Please try again.'
error
});
}
});
Data posted in postman:
Link: http://localhost:3000/api/framework/add/6233277f411377367f8ad1c0/6233277f411377367f8ad1c1
{
"controls":
{
"mainControl": "1-5",
"subControls": [{
"subControlNo": "1-4-1"
},
{
"subControlNo": "1-4-2"
}],
"controlDescription": "controlDescriptionTest"
}
}
Response:
{
"success": true,
"controls": {
"mainControl": "1-5",
"subControls": [
{
"subControlNo": "1-4-1"
},
{
"subControlNo": "1-4-2"
}
],
"controlDescription": "controlDescriptionTest"
}
}
Problem: I'm not getting any new data in mongodb , any idea if I'm approaching this the correct way? I'm guessing the data is posted correctly and It's a problem with saving it to the database
Picture of my schema: I want to be able to add elements under the controls:
First if you want your code to insert and not update you should use insertOne and not updateOne, regarding an "update" operation I can see 2 potential "issues" here:
req.params.frameworkId and req.params.domainId come as string type. And I assume the _id field is type ObjectId and not string.
To fix this you just need to cast it to the proper type, like so:
import { ObjectId } from 'mongodb';
...
{ _id: new ObjectId(req.params.frameworkId) }
Both parameters are "querying" the same field (_id), unless this is intentional somehow if these values are different it will never find a document to match, this should be changed.
Lastly if you want to update an existing object if exists, and if not insert then you should use updateOne with the upsert option:
await Framework.updateOne(query, { $push: { domains: control } }, { upsert: true }).exec();

How can i add, update, delete nested objects in mongoDB

I'm new to mongoDB and backend stuffs. I've a nested MongoDB model schema. I need to update, delete and add in that nested objects/array. How can I do that ?
How can I delete/add/update item from columns array and resume array.
const userSchema = new Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
},
columns: [
{
title: {
type: String,
required: true,
},
resumes: [
{
name: {
type: String,
required: true,
},
resume: {
type: String,
required: true,
},
},
],
},
],
});
const Users = mongoose.model('Users', userSchema);
This is my schema
To add new item to the columns array:
let newData = {title: "New Title", resumes: []}
let userData = await User.findByIdAndUpdate(userID, {
$push: {
columns: newData,
},
});
To add new item to the resumes array inside columns:
let newData = {name: "New Name", resume: "New Resume"}
let userData = await User.updateOne(
{
_id: mongoose.Types.ObjectId("60f54774761788cd80f56xxx"),
"columns._id": mongoose.Types.ObjectId("60f54774761788cd80f56xxx"),
},
{
$push: { "columns.$.resumes": newData },
}
);
Similarly, you can use $pull operator to remove an object from the array, and $(update) to update the element inside the array

updating array inside another array in mongoose

I have mongoose model like below,
var product = new mongoose.Schema({
productName: String,
manufacturer: String,
shotDescription: String,
longDescription: String,
colorNsize: [{
color: String,
size: [{
sizeId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'productSizes'
},
MRP: Number,
storePrice: Number,
stock: Number
}]
}]
});
I am trying update the document's colorNsize field. My goal is to push new items into the size array of the colorNsize array.
As size is the array inside another array, i am having tough time to update.
I tried the following
product.findOneAndUpdate({
_id: req.body.productId
}, {
$push: {
colorNsize: {
color: req.body.color,
$push: {
size: req.body
}
}
}
}, {
new: true
},
function (err, data) {
return res.json(data);
});
Can anyone help me in this?
You could try something like this:
product.findOneAndUpdate({ _id: req.body.productId },
{
$set: {colorNsize.color: req.body.color},
$push: {colorNsize.size: req.body}
},
{ upsert: true, new: true},
function (err, data) {
if(err){ return res.json(err);}
else{return res.json(data);}
});

Mongoose Schema - How to create a schema where one of the fields is an array of key-value pairs?

var db = require('../db');
var post = db.Schema({
msgtype: { type: Number },
msgtext: { type: String },
sender: { type: String },
recipients: { xxxxxx },
created_on: { type: Date }
});
module.exports = db.model('Post', post);
I want the field, recipients, is of the type - array of
{
email: {type: String},
read: {type: Boolean }
}.
Just declare recipients as an array:
...
recipients: [{
email: String,
read: Boolean
}]
...
To search for a recipient item, by the email field, do:
Post.findOne({'recipients.email': 'peter.w#gmail.com'}, function (err, doc) {
if (!err) console.log(doc);
});
To update an item, just do:
Post.findOneAndUpdate(
{ 'recipients.email': 'peter.w#gmail.com' },
{
'$set': {
'recipients.$.read': true
}
},
function(err, doc) {
});
This way will set true to all recipients whose email is peter.w#gmail.com of the first document found.

Resources