Update MongoDB object in object by id - javascript

Model:
const projectSchema = new Schema({
name: {
type: String,
maxlength: 50
},
description: {
type: String
},
projectLead: {
type: String
},
start: {
type: String
},
end: {
type: String
},
projectType: {
type: String
},
claimId: {
type: String
},
organization: {
type: String
},
seats: [{
id: String,
employee: String,
role: String,
start: String,
end: String,
workload: Number,
skills: Array,
approved: Boolean
}]
}, {
timestamps: true
})
Model response example:
{
"project": {
"_id": "5cab4b9bc9b29a7ba2363875",
"name": "Project Title",
"description": "Project description",
"projectLead": "email#email",
"start": "2018-06-01T09:45:00.000Z",
"end": "2019-06-31T09:45:00.000Z",
"claimId": "AIIIIII",
"organization": "Company ACE",
"seats": [
{
"skills": [
"Node.js",
"Vue.js"
],
"_id": "5cab548e5cefe27ef82ca313",
"start": "2018-06-01T09:45:00.000Z",
"end": "2019-06-31T09:45:00.000Z",
"role": "Developer",
"approved": false,
"workload": 20,
"employee": ''
}
],
"createdAt": "2019-04-08T13:24:43.253Z",
"updatedAt": "2019-04-08T14:02:54.257Z",
"__v": 0
}
}
Controller:
exports.updateSeatEmployee = async (req, res, next) => {
try {
const project = await Project.findOneAndUpdate({
"seats._id": req.params.id
}, {
"seats.employee": req.body.employee
}, {
new: true
})
console.log("project", project);
return res.json({
project: project
})
} catch (error) {
next(error)
}
}
Debugger:
Mongoose: users.createIndex({ email: 1 }, { unique: true, background:
true }) { sub: '5cab48ebec24577ab3329fcd', iat: 1554729210 }
Mongoose: users.findOne({ _id: ObjectId("5cab48ebec24577ab3329fcd") },
{ projection: {} })
Mongoose: projects.findAndModify({ 'seats._id':
ObjectId("5cab529bcafa027e30ee229c") }, [], { '$setOnInsert': {
createdAt: new Date("Mon, 08 Apr 2019 14:45:56 GMT") }, '$set': {
'seats.$.employee': 'email#email.com', updatedAt: new
Date("Mon, 08 Apr 2019 14:45:56 GMT") } }, { new: true, upsert: false,
remove: false, projection: {} }) (node:33302) DeprecationWarning:
collection.findAndModify is deprecated. Use findOneAndUpdate,
findOneAndReplace or findOneAndDelete instead.
project null
I want to search for a specific object in seats by its id.
This specific seat should be update. In my case I want to update the employee field.
If I do a findOne({"seats._id": req.params.id}) I get the project back but findOneAndUpdate returns null.

You need the $ positional operator since seats is an array and you should use $set operator if you want to update just one field
const project = await Project.findOneAndUpdate({
"seats._id": req.params.id
}, {
$set: { "seats.$.employee": req.body.employee }
}

Related

How to receive object information from within an array in mongoose?

I have two models, a posts model and a category model where I have an array that stores posts by objectId
Category Model
const mongoose = require('mongoose');
const CategorySchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
color: {
type: String,
required: true,
},
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post',
required: false,
}],
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Category", CategorySchema);
Post model
const mongoose = require('mongoose');
const PostSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
img: {
type: String,
required: true,
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
desc: {
type: String,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Post", PostSchema);
So I created a get by id category controller
const Category = require('../../models/Category');
class FindCategory {
async find(req, res) {
const { id } = req.params;
try {
const category = await Category.findById(id);
return res.status(200).json(category);
} catch (err) {
return res.status(500).json(err);
}
}
}
module.exports = new FindCategory();
The problem is that when I make this request in my postman, it returns me for example
{
"_id": "63ac925d872445065a588f61",
"name": "Games",
"color": "#ff914d",
"posts": [
"63ac9cbccec4d9f35c4f4d1f"
],
"createdAt": "2022-12-28T19:00:45.847Z",
"updatedAt": "2022-12-28T19:49:47.119Z",
"__v": 0
}
But I would like to render the information of each post inside the "posts" array, something like that for example
{
"_id": "63ac925d872445065a588f61",
"name": "Games",
"color": "#ff914d",
"posts": [
"name": "red dead",
"img": "example.png",
"category": "games",
"desc": "test,
],
"createdAt": "2022-12-28T19:00:45.847Z",
"updatedAt": "2022-12-28T19:49:47.119Z",
"__v": 0
}
You should use the populate function provided by mongoose: https://mongoosejs.com/docs/populate.html#setting-populated-fields
Category.
findById(...).
populate('posts')

Mongoose, updated nested array

My question is:
How can I query in the nested arrays?
I want to change value in key "likeUp" which is nested inside object in array "usersWhoLiked". Where "usersWhoLiked" is nested in array "comments"
How Can I do that with mongoose ?
Request that I wrote beneath... do not work, but is very similar to answer given in StackOverflow post: Mongoose update update nested object inside an array
This is my request to db with updateOne:
try {
const response = await Comments.updateOne(
{
productId,
comments: { $elemMatch: { usersWhoLiked: { $elemMatch: { userId } } } },
},
{
$set: { 'comments.$[outer].usersWhoLiked.$[inner].likeUp': likes.up },
},
{
arrayFilters: [{ 'outer._id': commentId }, { 'inner._userId': userId }],
}
).exec();
return res.status(201).json({ response });
} catch (err) {
console.log(err);
return res.send(err);
}
This is the collection, that I am trying to update:
{
"_id": {
"$oid": "6307569d2308b78b378cc802"
},
"productId": "629da4b6634d5d11a859d729",
"comments": [
{
"userId": "62f29c2c324f4778dff443f6",
"userName": "User",
"date": "2022.08.25",
"confirmed": true,
"likes": {
"up": 0,
"down": 0
},
"content": {
"rating": 5,
"description": "Nowy komentarz"
},
"_id": {
"$oid": "630756b22308b78b378cc809"
},
"usersWhoLiked": [
{
"userId": "62f29c2c324f4778dff443f1",
"likeUp": true,
"_id": {
"$oid": "6307572d2308b78b378cc80e"
}
},
{
"userId": "62f29c2c324f4778dff443f2",
"likeUp": true,
"_id": {
"$oid": "6307572d2308b78b378cc80c"
}
}
]
}
],
"__v": 0
}
Mongooes schema for comment collection:
const commentSchema = new Schema({
productId: String,
comments: [
{
userId: String,
userName: String,
date: String,
confirmed: Boolean,
likes: {
up: {
type: Number,
default: 0,
},
down: {
type: Number,
default: 0,
},
},
content: {
rating: Number,
description: String,
},
usersWhoLiked: [{ userId: String, likeUp: Boolean }],
},
],
});
I guess the problem is with your arrayFilters operator, because you are trying to filter by field _userId which does not exist:
arrayFilters: [{ 'outer._id': commentId }, { 'inner._userId': userId }],
I managed to update the likeUp value using the following query:
db.collection.update({
_id: ObjectId("6307569d2308b78b378cc802")
},
{
$set: {
"comments.$[user].usersWhoLiked.$[like].likeUp": false
}
},
{
arrayFilters: [
{
"user._id": ObjectId("630756b22308b78b378cc809")
},
{
"like.userId": "62f29c2c324f4778dff443f1"
}
]
})
Try it on MongoDB playground: https://mongoplayground.net/p/XhQMNBgEdhp

Express - Find an object in MongoDB by id and save its data to array

I have two models: Meal and Ingredient. Here are the schemas:
const mealSchema = new Schema({
title: { type: String, required: true },
image: { type: String, required: false },
ingredients: [{
ingredient: { type: mongoose.Types.ObjectId, required: true, ref: 'Ingredient' },
amount: { type: Number, required: true }
}],
})
const ingredientSchema = new Schema({
name: { type: String, required: true },
unit: { type: String, required: true },
category: { type: String, required: false },
is_vege: { type: Boolean, required: true }
});
When I create the meal, I provide the ingredients as an array in POST request body.
const createMeal = async (req, res, next) => {
const { title, ingredients } = req.body;
// ingredientArray consists of objects with two keys:
// <String> ingredient - id of the associated ingredient in database
// <Number> amount - amount of the ingredient
ingredientArray = JSON.parse(ingredients)
const createdMeal = new Meal({
title,
image: req.file.path,
ingredients: ingredientArray
});
try {
await createdMeal.save();
} catch (err) {
const error = new HttpError('Error occurred, try again later', 500);
return next(error);
}
res.status(201).json(createdMeal);
}
This is the object that is created:
{
"_id": "62ea4531bd7e04fa740e2fee",
"title": "Spaghetti",
"image": "uploads\\images\\8da09ec6-3684-4af5-a513-f90155ddafd8.jpeg",
"ingredients": [
{
"ingredient": "62ea37251212c738a0ce9cee",
"amount": 100,
"_id": "62ea4531bd7e04fa740e2fef",
"id": "62ea4531bd7e04fa740e2fef"
},
{
"ingredient": "62ea371ab9392f3e0107c541",
"amount": 10,
"_id": "62ea4531bd7e04fa740e2ff0",
"id": "62ea4531bd7e04fa740e2ff0"
}
],
"__v": 0,
"id": "62ea4531bd7e04fa740e2fee"
}
I need my "ingredients" list to find the actual ingredient in the database and save its complete data so that the result would look something like this:
"ingredients": [
{
"ingredient": "62ea37251212c738a0ce9cee",
"amount": 100,
"name": "Pasta",
"unit": "g",
"category": "pastas",
"is_vege": true,
"_id": "62ea4531bd7e04fa740e2fef",
"id": "62ea4531bd7e04fa740e2fef"
},
{
"ingredient": "62ea371ab9392f3e0107c541",
"amount": 200,
"name": "Tomato",
"unit": "g",
"category": "vegetables",
"is_vege": true,
"_id": "62ea4531bd7e04fa740e2ff0",
"id": "62ea4531bd7e04fa740e2ff0"
}
]
EDIT: Ideally, the ingredient should be found BEFORE saving, because I want to run some calculations before the meal ends up in the database.
I figured it out. It took a single line of code:
let createdMeal = new Meal({
title,
image: req.file.path,
prep_time,
ingredients: ingredientArray
});
createdMeal = await createdMeal.populate({ path: 'ingredients.ingredient' });
Documentation:
https://mongoosejs.com/docs/populate.html

MongooseJS: How to remove 1 object inside Array in Array of Objects

Hi MongooseJS experts!
I'm new in MongooseJS, This is my 2nd day of solving this problem but I can't find a working solution to this.
Thank you in advance!
My Delete method
Cart.updateOne(
{ "content.merchantId": req.body.merchantId },
{ $pull: { "content.items._id": req.body.productId } },
{ new: true },
function (error, result) {
if (error) { }
else if (result) { }
}
);
Schema
const CartSchema = new Schema({
customerId: {
type: String,
required: true,
},
content: {
merchantName: {
type: String,
required: true,
},
merchantId: {
type: String,
required: true,
},
items: [],
},
});
Sample JSON
[
{
"content": {
"merchantName": "SAMPLE_MERCHANT_NAME",
"merchantId": "SAMPLE_MERCHANT_ID",
"items": [
{
"_id": "SAMPLE_ID",
"title": "SAMPLE TITLE",
}
]
},
"_id": "618220e83966345ab5d451cd",
"__v": 0
},
]
Error message
Cannot use the part (_id) of (content.items._id) to traverse the element ({items: [{ _id: "SAMPLE_ID", title: "SAMPLE TITLE"}] })
you should use like this
db.collection.update({
"content.merchantId": "SAMPLE_MERCHANT_ID"
},
{
$pull: {
"content.items": {
"_id": "SAMPLE_ID"
}
}
},
{
new:true
},
)
https://mongoplayground.net/p/Ou26tab2mBU

Mongoose populate does not populate array

I have struggled with the mongoose.model.populate function for hours now. I have even tried directly copying and pasting several solutions without luck.
I have a User model which is supposed to contain an array of 'Dilemmas' which he/she has created, but I have been unable to populate it.
Here are the models as well as the implementation of populate().
User.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
dilemmas: [
{
type: Schema.Types.ObjectId,
ref: "Dilemma"
}
]
});
module.exports = User = mongoose.model("User", UserSchema, "users");
Dilemma.js
const mongoose = require("mongoose");
const slug = require("mongoose-slug-generator");
const Schema = mongoose.Schema;
mongoose.plugin(slug);
// Create Schema
const DilemmaSchema = new Schema({
creator: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
title: {
type: String
},
slug: {
type: String,
slug: "title"
},
red: {
type: String,
required: true
},
blue: {
type: String,
required: true
},
red_votes: {
type: Number,
default: 0,
required: true
},
blue_votes: {
type: Number,
default: 0,
required: true
},
likes: [
{
user: {
type: Schema.Types.ObjectId,
ref: "User"
}
}
],
comments: [
{
user: {
type: Schema.Types.ObjectId,
ref: "User"
},
text: {
type: String,
required: true
},
author: {
type: String
},
avatar: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
});
module.exports = Dilemma = mongoose.model("Dilemma", DilemmaSchema, "dilemmas");
Routes.js
// #route GET api/users/profile
// #desc Gets logged in user's profile
// #access Private
router.get(
"/profile",
passport.authenticate("jwt", { session: false }),
(req, res) => {
User.find({ username: req.user.username })
.populate("dilemmas")
.then(user => {
if (!user) {
errors.nouser = "There is no user";
return res.status(404).json(errors);
}
res.json(user);
})
.catch(err => res.status(400).json(err));
}
);
JSON Response
[
{
"_id": "5b807beef770e7c7e6bf7ce0",
"dilemmas": [],
"username": "Jonas",
"email": "Mohrdevelopment#gmail.com",
"password": "$2a$10$QaqljS9x08YQ9N9EuCBTpO114ZJUFuVxAV80xMzImNi8eW2frPg0C",
"date": "2018-08-24T21:43:10.411Z",
"__v": 0
}
]
JSON Dilemmas response
[
{
"red_votes": 0,
"blue_votes": 0,
"_id": "5b80975f6e47fecba621f295",
"user": "5b807beef770e7c7e6bf7ce0",
"title": "Am i the real author asdsdasd?",
"red": "This is the red dilemma",
"blue": "This is the blue dilemma",
"likes": [],
"comments": [],
"date": "2018-08-24T23:40:15.381Z",
"slug": "am-i-the-real-author-asdsdasd",
"__v": 0
},
{
"red_votes": 0,
"blue_votes": 0,
"_id": "5b808e789bc36bcae8c6c3ad",
"creator": "5b807beef770e7c7e6bf7ce0",
"title": "Am i the real author?",
"red": "This is the red dilemma",
"blue": "This is the blue dilemma",
"likes": [],
"comments": [],
"date": "2018-08-24T23:02:16.565Z",
"slug": "am-i-the-real-author",
"__v": 0
}
]
JSON Users response
{
"_id": {
"$oid": "5b807beef770e7c7e6bf7ce0"
},
"dilemmas": [],
"username": "Jonas",
"email": "Mohrdevelopment#gmail.com",
"password": "$2a$10$QaqljS9x08YQ9N9EuCBTpO114ZJUFuVxAV80xMzImNi8eW2frPg0C",
"date": {
"$date": "2018-08-24T21:43:10.411Z"
},
"__v": 0
}
I just encountered a similar issue myself. Populating a ref worked, but populating an array of refs did not. I was able to get the array populate to work by explicitly specifying the model name in the populate call, e.g.:
User.find({ ... }).populate({
path: 'dilemmas',
model: 'Dilemma',
});
I don't know why this makes a difference, when the name of the referenced model is already specified in the schema.
Have you tried this?
User.find({ username: req.user.username })
.populate("dilemmas")
.exec() // <-- add exec() to perform the search
.then(user => {
...
})
Did you check the documentation here?
https://mongoosejs.com/docs/populate.html#refs-to-children
It shows a similar setup (with Authors and Stories.) It mentions 'pushing' stories to be able to use a find / populate combo.

Categories

Resources