MongoDB - How to Update or Insert object in array - reactjs

I have the following collection
{
"likes": [],
"_id": "6086f47a3e8c0411f0a66d22",
"creator": "dimer",
"picture": "",
"title": "",
"body": "hello world",
"comments": [
{
"isReady": true,
"likes": [],
"_id": "6086fcf33e8c0411f0a66d25",
"creatorId": "607e50a16e852544d41a1d9d",
"creator": "dimer",
"body": "hello world",
"replies": [],
"timestamp": 1619459315854
},
],
"createdAt": "2021-04-26T17:12:26.632Z",
"updatedAt": "2021-04-27T04:22:28.159Z",
"__v": 0
},
I want to push into comment.replies a new reply if the comment and the post exists.
How to Update or Insert object into a nested array with conditions?
I tried this:
module.exports.createReply = async (req, res) => {
const user_ID = req.body.creatorId;
const post_ID = req.params.id;
const comment_ID = req.body.commentId;
if (!ID.isValid(user_ID) && !ID.isValid(post_ID) && !ID.isValid(comment_ID)) {
return res.status(400).send("ID unknown");
}
try {
console.log("hello woorld");
const reply = {
creatorId: user_ID,
creator: req.body.creator,
body: req.body.body,
timestamp: new Date().getTime(),
};
console.log("reply", reply);
await PostModel.findById(post_ID, (err, docs) => {
console.log(comment_ID);
const comment = docs.comments.find((comment) =>
comment._id.equals(comment_ID)
);
console.log("comment", comment);
if (!comment) return res.status(404).send("comment not found" + err);
comment.replies = [...comment.replies, reply];
return docs.save((err, docs) => {
if (!err) return res.status(200).send(docs);
return res.status(400).send(err);
});
});
} catch (error) {
return res.status(400).send(err);
}
};
I think I'm not reaching the replies because I'm getting this error:
{
"errors": {
"comments.4.creator": {
"name": "ValidatorError",
"message": "Path `creator` is required.",
"properties": {
"message": "Path `creator` is required.",
"type": "required",
"path": "creator"
},
"kind": "required",
"path": "creator"
}
},
"_message": "post validation failed",
"name": "ValidationError",
"message": "post validation failed: comments.4.creator: Path `creator` is required."
}
This is my model:
const nongoose = require("mongoose");
const PostSchema = nongoose.Schema(
{
creatorId: {
type: String,
// trim: true,
// required: true,
},
creator: {
type: String,
trim: true,
required: true,
},
title: {
type: String,
maxlength: 80,
},
body: {
type: String,
trim: true,
maxlength: 250,
required: true,
},
picture: {
type: String,
},
video: {
type: String,
},
likes: {
type: [String],
require: true,
},
comments: {
required: true,
type: [
{
isReady: {
type: Boolean,
default: true,
},
creatorId: {
type: String,
required: true,
},
creator: {
type: String,
required: true,
},
timestamp: Number,
body: {
type: String,
required: true,
trim: true,
},
likes: {
type: [String],
required: true,
},
replies: {
require: true,
type: [
{
isReady: {
type: Boolean,
default: true,
},
creatorId: {
type: String,
required: true,
},
creator: {
type: String,
required: true,
},
body: {
type: String,
required: true,
trim: true,
},
timestamp: Number,
},
],
},
},
],
},
},
{
timestamps: true,
}
);
module.exports = nongoose.model("post", PostSchema);

Like the error says, Path creator is required.
Make sure the reply has the 'creator' field.

To get the updated document in the update’s return value, you need to use findOneAndUpdate 1 or findAndModify methods. Both the methods have a parameter where you can specify to return the updated document. Note that the Mongoose ODM has corresponding methods, but may have slightly different syntax.
My solution:
module.exports.createReply = async (req, res) => {
const user_ID = req.body.creatorId;
const post_ID = req.params.id;
const comment_ID = req.body.commentId;
if (!ID.isValid(user_ID) && !ID.isValid(post_ID) && !ID.isValid(comment_ID)) {
return res.status(400).send("ID unknown");
}
try {
const reply = {
creatorId: user_ID,
creator: req.body.creator,
body: req.body.body,
timestamp: new Date().getTime(),
};
const query = { _id: post_ID };
const update = { $push: { "comments.$[elem].replies": reply } };
const options = { new: true, arrayFilters: [{ "elem._id": comment_ID }] };
await PostModel.findOneAndUpdate(query, update, options);
let updated = await PostModel.findOne({ _id: post_ID });
return res.status(200).send({
data: updated.comments.find((comment) => comment._id.equals(comment_ID)),
});
} catch (err) {
return res.status(400).send({ err: err });
}
};

Related

How do I update individual fields in nested objects that are in arrays in MongoDB using Mongoose?

This is my first post so please bear with me. I am building a LinkedIn clone and I am trying to keep track of the work experience, projects and courses of the users, and those will be kept in an array of objects inside of the User schema. Now let's say a user will try to add or update one of the elements in one of those arrays, I have the user ID and I am passing it to findOneAndUpdate() as the filter.
Here is my User schema:
const userSchema = new mongoose.Schema({
user_id: {
type: String,
required: [true, 'User ID required.'],
unique: true,
immutable: true,
},
name: {
type: String,
required: [true, 'Name required.'],
},
email: {
type: String,
required: [true, 'Email required.'],
unique: true,
lowercase: true,
immutable: true,
},
title: {
type: String,
},
location: {
type: String,
},
phone_number: {
type: String,
},
contact_email: {
type: String,
},
photo: {
type: String,
},
website: {
type: String,
},
backdrop: {
type: String,
},
summary: {
type: String,
},
work: {
type: String,
},
connections: {
type: Number,
},
projects: [
{
title: {
type: String,
},
description: {
type: String,
},
start_date: {
type: Date,
},
end_date: {
type: Date,
},
technologies: {
type: String,
},
picture: {
type: String,
},
},
],
skills: [{
skill: {
name: {
type: String,
},
level: {
type: String,
},
},
}],
experience: [
{
company: {
type: String,
},
logo: {
type: String,
},
title: {
type: String,
},
location: {
type: String,
},
start_date: {
type: Date,
},
end_date: {
type: Date,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
},
logo: {
type: String,
},
degree: {
type: String,
},
location: {
type: String,
},
start_date: {
type: Date,
},
end_date: {
type: Date,
},
description: {
type: String,
},
},
],
languages: [
{
name: {
type: String,
},
level: {
type: String,
},
},
],
awards: [
{
title: {
type: String,
},
date: {
type: Date,
},
awarder: {
type: String,
},
summary: {
type: String,
},
},
],
courses: [
{
title: {
type: String,
},
number: {
type: String,
},
school: {
type: String,
},
start_date: {
type: Date,
},
end_date: {
type: Date,
},
description: {
type: String,
},
},
],
});
And in my UserController.ts file, I tried using this:
const updateUser = async (req: Request, res: Response) => {
try {
const filter = { user_id: req.body.user_id };
const update = req.body;
const updatedUser = await User.findOneAndUpdate(filter, update, {
new: true,
upsert: true,
});
res.status(201).json({
status: 'success',
data: {
user: updatedUser,
},
});
} catch (err) {
res.status(400).json({
status: `ERROR: ${err}`,
message: 'error updating user',
});
}
};
And in my request using the format of the schema but that didn't work out as expected. I know mongoose will automatically give it an _id field to each of the individual objects in the array, but again, I have had no luck updating them. I tried sending a PATCH request with this as the body to add a skill like so:
{
"user_id": "xxxxxxxxxxxxxxxx",
"title": "Mr.",
"skills" : {
"name": "Flute",
"level": "Novice"
}
}
And this was the response I got. It created a skill but didnt add the data in the skill object:
{
"status": "success",
"data": {
"user": {
"_id": "63d3715f2ef9698667230a53",
"user_id": "xxxxxxxxxxxxxxxx",
"name": "Jonathan Abitbol",
"email": "yoniabitbol1#gmail.com",
"projects": [],
"skills": [
{
"_id": "63d4068d2df30c9e943e4608"
}
],
"experience": [],
"education": [],
"languages": [],
"awards": [],
"courses": [],
"__v": 0,
"title": "Mr."
}
}
}
Any help on how to add/edit the nested objects would be appreciated.

I am having difficulty accessing this nested array to carry out an update

SCHEMA
Below is my schema structure, kindly correct me if I am getting it wrong. I want to be able to update the ConnectState from false to true using an ObjectId
phones: {
type: String,
required: true,
},
User: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
// required: true,
},
Userpost: {
type: mongoose.Schema.Types.ObjectId,
ref: "userpost",
// required: true,
},
friendshipStatus: [
{
isFriend: {
FProfile: {
type: mongoose.Schema.Types.ObjectId,
ref: "profile",
},
ConnectStatus: {
type: Boolean,
default: false,
},
},
},
],
});
What I have tried
I want to update the Boolean value on ConnectStatus from false to true. I know I am getting the process wrong.
const result = await Profile.updateOne(
{ "friendshipStatus.isFriend.FProfile": uid },
{ $set: { "friendshipStatus.$.isFriend.ConnectStatus": true } },
{ arrayFilters: [{ "friendshipStatus.isFriend.FProfile": uid }] }
);
Try with:
const result = await Profile.update(
{ 'friendshipStatus.isFriend.FProfile': uid },
{ $set: { 'friendshipStatus.$.isFriend.ConnectStatus': true } },
);

user_team is not associated to team

I'm new to sequelize as a user and I use the 'many to many' option in the team situation. I created my code but : user_team is not associated to team! i am getting error how can i fix it. I'm doing it for a task, I would be very happy if you help me.tanks
If the structure is also wrong, can you tell me what my mistakes are?
userteam.js
module.exports = (sequelize, DataTypes) => {
const UserTeam = sequelize.define(
"user_team",
{
user_team_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
user_id: {
type: DataTypes.INTEGER,
primaryKey: false,
references: {
model: "user",
key: "user_id",
},
onDelete: "cascade",
onUpdate: "cascade",
unique: "unique-team-per-user",
},
team_id: {
type: DataTypes.INTEGER,
primaryKey: false,
references: {
model: "team",
key: "team_id",
},
onDelete: "cascade",
onUpdate: "cascade",
unique: "unique-team-per-user",
},
},
{ timestamps: false, tableName: "user_team", underscored: true }
);
UserTeam.associate = (models) => {
UserTeam.belongsTo(models.User, {
foreignKey: "user_id",
targetKey: "user_id",
as: "User",
});
UserTeam.belongsTo(models.Team, {
foreignKey: "team_id",
targetKey: "team_id",
as: "Team",
});
};
return UserTeam;
};
user.js
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define(
"user",
{
user_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
},
{ timestamps: true, tableName: "user", underscored: true }
);
User.associate = (models) => {
User.hasMany(models.Todo, {
as: "todos",
foreignKey: "userId",
});
User.hasMany(models.Team, {
as: "teams",
foreignKey: "admin",
});
User.belongsToMany(models.Team, {
as: "TeamsForUser",
through: models.UserTeam,
foreignKey: "user_id",
});
};
return User;
};
team.js
module.exports = (sequelize, DataTypes) => {
const Team = sequelize.define(
"team",
{
team_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
teamName: {
type: DataTypes.STRING,
allowNull: false,
},
admin: {
type: DataTypes.INTEGER,
allowNull: false,
},
},
{ tableName: "team", underscored: true }
);
Team.associate = (models) => {
Team.belongsTo(models.User, {
as: "user",
foreignKey: "admin",
});
Team.belongsToMany(models.User, {
as: "UserInTeam",
through: models.UserTeam,
foreignKey: "team_id",
});
};
return Team;
};
controller.js
const getAll = async (req, res, next) => {
try {
const myTeams = await Team.findAll({
include: [{ model: UserTeam }],
});
myTeams.forEach((element) => {
console.log(element.get());
});
return res.status(200).json(myTeams);
} catch (err) {
console.log(err.message);
res.status(500).json({ message: err });
}
};
i solved this problem
just add to index database config js
db.users.belongsToMany(db.team, {
as: "teams",
through: "user_team",
foreignKey: "user_id",
});
db.team.belongsToMany(db.users, {
as: "users",
through: "user_team",
foreignKey: "team_id",
});
enter code here

My updated data does not reflect in even it is status 200

I want to increase the score of a player by updating it. Here is the call.
const addPlayerScore = async (score, currentPlayer) => {
try {
const addScore = {
score: score,
};
const { data } = await fetchContext.authAxios.patch(
`/facilitator/add-score-player-team-one/${currentPlayer}`,
addScore
);
console.log(data.message);
} catch (error) {
const { data } = error.response;
console.log(data.message);
}
};
the currentPlayer takes the id of player. Which I passed into the params.
here is the request;
exports.addscoreplayerteamone = async (req, res) => {
try {
const { score } = req.body;
const existLive = await LiveMatch.findOneAndUpdate(
{
'teamOne.players._id': req.params.id,
},
{
$set: {
$inc: {
'teamOne.players.$.scores': score,
},
},
},
{ new: true }
);
const addPlayerScore = await existLive.save();
res
.status(200)
.send({ message: "Added the player's score", addPlayerScore });
} catch (error) {
console.log(error);
return res.status(400).json({
message: 'There was a problem adding a score',
});
}
};
here is the schema;
const mongoose = require('mongoose');
const liveSchema = new mongoose.Schema(
{
schedule: {
type: mongoose.Types.ObjectId,
required: true,
},
user: {
type: mongoose.Types.ObjectId,
required: true,
},
teamOne: {
teamName: {
type: String,
required: true,
trim: true,
max: 50,
},
players: [
{
name: {
type: String,
required: true,
trim: true,
max: 50,
},
jerseyNumber: {
type: String,
required: true,
trim: true,
},
scores: {
type: Number,
default: 0,
trim: true,
},
fouls: {
type: Number,
trim: true,
},
},
],
score: {
type: Number,
trim: true,
default: 0,
},
},
teamTwo: {
teamName: {
type: String,
required: true,
trim: true,
max: 50,
},
players: [
{
name: {
type: String,
required: true,
trim: true,
max: 50,
},
jerseyNumber: {
type: String,
required: true,
trim: true,
},
scores: {
type: Number,
default: 0,
trim: true,
},
fouls: {
type: Number,
trim: true,
},
},
],
score: {
type: Number,
trim: true,
default: 0,
},
},
gameEvent: {
type: String,
required: true,
enum: ['basketball', 'volleyball', 'soccer'],
},
winner: {
type: String,
trim: true,
},
loser: {
type: String,
trim: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model('live-match', liveSchema);
it returns status 200 but it does not increments the score of the player in the database nor being reflected in the frontend.
Try this:
const existLive = await LiveMatch.findOneAndUpdate(
{
'teamOne.players._id': req.params.id,
},
{
$inc: { 'teamOne.players.scores': score }
},
{
new: true
}
);

Mongoose findByIdAndUpdate : can't update an array field

I'm new to mongoose and i have a problem.
In my app, i have a Travel model like this:
const travelSchema = new mongoose.Schema({
title: {
type: String,
required: [true, 'Please add a title'],
trim: true,
maxlength: [50, 'Title can not be more than 50 characters'],
},
cities: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'City',
},
],
});
and a City model like this :
const citySchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
},
location: {
type: {
type: String,
enum: ['Point'],
required: true,
},
coordinates: {
type: [Number],
required: true,
},
},
travels: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Travel',
},
],
});
So when i delete a travel, i want to remove the travel_id from the 'travels' field of the cities which are concerned by the travel.
Here i am:
exports.deleteTravel = asyncHandler(async (req, res, next) => {
const travel = await Travel.findByIdAndDelete(req.params.id);
travel.cities.map(cityId => {
City.findByIdAndUpdate(
cityId,
{ travels: travels.filter(id => id !== travel._id) },
{
new: true,
runValidators: true,
}
);
});
res.status(200).json({ success: true, data: {} });
});
I got this error message: Error: travels is not defined
Do you have any idea why?
Many thanks !
It's working like this :)
exports.deleteTravel = asyncHandler(async (req, res, next) => {
const travel = await Travel.findByIdAndDelete(req.params.id);
travel.cities.map(async cityId => {
await City.findByIdAndUpdate(
cityId,
{ $pull: { travels: travel._id } },
{
new: true,
runValidators: true,
}
);
});

Resources