How to insert new data in a object array in mongoose? - node.js

I am trying to insert a new data in a specific array of that server, since new data will be added while the user speaks in several servers. I mean, if the user receives a warn, it is stored in the array of the server in which the command is executed and not in another server, and vice versa and it is carried out in another server
warnSet = await User.findOne(
{
_id: user.id,
"warns._id": message.guild.id,
},
(err, usuario) => {
if (err) console.error(err);
if (!usuario) {
const newUser = new User({
_id: user.id,
userName: user.username,
warns: [
{
_id: message.guild.id,
warn: 1,
},
],
});
newUser.save().catch((err) => console.error(err));
return;
} else {
usuario
.updateOne(
{ "warns._id": message.guild.id },
{
$set: {
"warns.warn": 2,
},
}
)
.catch((err) => console.error(err));
return;
}
}
);
The Model:
const mongoose = require("mongoose");
const userSchema = mongoose.Schema({
_id: Number,
userName: String,
warns: [
{
_id: Number,
warn: Number,
},
],
});
module.exports = mongoose.model("User", userSchema, "user");

Related

NodeJS, Mongoose prevent Push to write if same data is already in the array

I have app where I have Users. Every user can be an owner of an item or multiple items..
If user is already owner of that item prevent to push the item object into array, if already exists.
I already tried different solutions (I will write what I tried in the end of the question).
User model:
import * as mongoose from "mongoose";
const Schema = mongoose.Schema;
const UserSchema = new mongoose.Schema({
email: { type: String, required: true, min: 6, max: 255 },
password: { type: String, required: true, min: 4, max: 1024 },
role: { type: String, required: true, default: "User" },
owners: [
{
type: Schema.Types.ObjectId,
ref: "Owners",
required: false,
},
],
});
module.exports = mongoose.model("Users", UserSchema);
Add owner to user controller:
exports.addOwnerToUser = async (req: Request, res: Response) => {
try {
console.log("here");
let ObjectID = require("mongodb").ObjectID;
const mongoose = require("mongoose");
const user = {
email: req.body.email,
ownerId: req.body.ownerId,
};
const updatedUser = await User.findOneAndUpdate(
{
_id: req.params.userId,
owners: { $ne: req.body.ownerId },
},
{
$push: { owners: req.body.ownerId },
}
);
res.status(201).json({ sucess: true, msg: "User updated sucessfully" });
} catch (err) {
res.status(404).json(err);
}
};
I already tried solutions like this, but nothing works as expected.. (check the commented code)
exports.addOwnerToUser = async (req: Request, res: Response) => {
try {
console.log("here");
let ObjectID = require("mongodb").ObjectID;
const mongoose = require("mongoose");
// add get user and find if he already has this id.. if has then json 200
// if not i execute line 230
const user = {
email: req.body.email,
ownerId: req.body.ownerId,
};
/* const updatedUser = await User.findOneAndUpdate(
{ _id: req.params.userId },
{
"ownerId.ownerId": {
$ne: ObjectID(req.body.ownerId),
},
},
{
$addToSet: {
"ownerId.ownerId": ObjectID(req.body.ownerId),
},
},
{
new: true,
}
); */
const updatedUser = await User.findOneAndUpdate(
/* {
_id: req.params.userId,
},
{
$addToSet: {
owners: req.body.ownerId,
},
},
{
new: true,
} */
{
_id: req.params.userId,
owners: { $ne: req.body.ownerId },
},
{
$push: { owners: { ownerId: req.body.ownerId } },
}
);
console.log(updatedUser);
/* const updatedUser = await User.findOneAndUpdate(
{ _id: req.params.userId },
{
$push: { ownerId: { ownerId: req.body.ownerId } },
}
);
console.log(updatedUser); */
// $addToSet: { members: { name: 'something', username: 'something' } }
/*
User.findByIdAndUpdate(req.params.user_id,{$set:req.body},{new:true}, function(err, result){
if(err){
console.log(err);
}
console.log("RESULT: " + result);
res.send('Done')
});
};
*/
res.status(201).json({ sucess: true, msg: "User updated sucessfully" });
} catch (err) {
res.status(404).json(err);
}
};

Saving an item that is specific to a user schema but not able to retrieve it back - mongoose

I have creared two schemas, user and medicine.
If a user adds medicines it should show up only in his/her account.
I am able to save the medicine ids to that specific user but i'm not able to get those medicines back i.e: medicines show for all the other users as well.
Here's the code snippet that saves meds to specific user:
const {userId, medName, medDescription, dose, medType, date, time} = req.body;
try {
const newMed = new MedsSchema({
userId,
medName,
medDescription,
dose,
medType,
date,
time,
});
await newMed.save().then(() => res.send({response: 'ok'}));
const specificUser = await User.findById({_id: userId});
specificUser.medicines.push(newMed);
await specificUser.save().then(
User.findOne(specificUser)
.populate('medicines')
.exec(function (err, docs) {
if (err) return handleError(err);
console.log(docs);
}),
);
Here's the userSchema:
const userSchema = new mongoose.Schema(
{
username: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
email: {
type: String,
unique: true,
required: true,
},
medicines: [{type: mongoose.Schema.Types.ObjectId, ref: 'MedsSchema'}],
},
{
toJSON: {
virtuals: true,
},
},
);
router.get('/getMeds/:Id', (req, res) => {
console.log(req.params.Id);
MedsSchema.find({userId: req.params.Id}, function (err, result) {
if (err) {
res.send(err);
} else {
res.send(result);
}
});
});
what do i add to this that will make me get only specific medicines for that specific user instead of getting all medicines?
Can you edit your first code snippet to
const { userId, medName, medDescription, dose, medType, date, time } = req.body;
try {
const user = await User.findOone({ _id: userId });
const newMed = await MedsSchema.create({
userId: user,
medName,
medDescription,
dose,
medType,
date,
time,
});
const specificUser = await User.findByIdAndUpdate({ _id: userId }, { $push: { medecines: newMed } });
return res.json({ newMed, specificUser })
};
and in the router
router.get('/getMeds/:Id', async (req, res) => {
console.log(req.params.Id);
const user = await User.findOne({ _id: req.params.Id }).populate({ path: 'medicines' })
console.log(user.medicines)
return res.json({meds: user.medicines})
});
also check the console results to see if everything is working

MongoDB array of objects update

I'm trying to update array of user information objects in mongoose.
I've stored the user core information in the login process, I want to update some of user information when user tries to make an order.
Here is the code for the model
const mongoose = require('mongoose');
const { ObjectId } = mongoose.Schema;
const userSchema = new mongoose.Schema(
{
name: String,
email: {
type: String,
required: true,
index: true,
},
role: {
type: String,
default: 'subscriber',
},
info: [
{ country: String },
{ city: String },
{ address: String },
{ phone: String },
{ birthdate: Date },
{ gender: { type: String, enum: ['Male', 'Female'] } },
],
// wishlist: [{ type: ObjectId, ref: "Product" }],
},
{ timestamps: true }
);
module.exports = mongoose.model('User', userSchema);
In my controller I'm getting the data from front-end react app as JSON format, I want to push some data to info which is an array of objects in the users model above.
exports.createOrder = async (req, res) => {
// Here I constract the data
const { plan, service, fullName, country, city, address } = req.body.order;
const { user_id } = req.body;
// This the method I tried
try {
const user = await User.updateOne(
{
_id: user_id,
},
{
$set: {
'info.$.country': country,
'info.$.city': city,
'info.$.address': address,
},
},
{ new: true }
);
if (user) {
console.log('USER UPDATED', user);
res.json(user);
} else {
res.json((err) => {
console.log(err);
});
}
const newOrder = await new Order({
orderPlan: plan,
orderService: service,
orderUser: user_id,
}).save();
console.log(newOrder);
console.log(req.body);
} catch (error) {
console.log(error);
}
};
I tired other solutions like
const user = await User.updateOne(
{
_id: user_id,
info: { $elemMatch: { country, city, address } },
},
{ new: true }
);
So do I need to reformat my model or there is a way to update this array of objects?
Option 1
Use $[]
db.collection.update(
{},
{ $set: { "info.$[i].country": "a1" }} ,
{ arrayFilters: [ { "i.country": "a" } ] }
)
Demo - https://mongoplayground.net/p/UMxdpyiKpa9
Option 2
if you know the index
Demo - https://mongoplayground.net/p/41S7qs6cYPT
db.collection.update({},
{
$set: {
"info.0.country": "a1",
"info.1.city": "b1",
"info.2.address": "c1",
"info.3.phone": "d1"
}
})
Suggestions -
Change info schema to object instead of an array

Why mongoose $pull does not remove item from an array

const userSchema = new mongoose.Schema({
name: String,
products: []
});
eg. User:
{ name: 'Steve', products: ['111a', '222b']}
I want to remove the product of given name from the user of given ID.
User.findByIdAndUpdate(userId, { $pull: { products: req.body.prodId } }, (err, user) => {
if (err) { res.send('error_3853852'); return; }
res.send('updated'); return;
})
As a result it is not removed and no error occured

Accessing a schema inside a schema using Express Router and MongoDG

I'm trying to create a route where it takes in a parameter for a username and then displays that users information. Only thing is, the username is in the user schema from when the user signs up. The profile schema references the user schema. How do I use the username parameter in the findOne call to display the users profile data?
User 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
}
});
module.exports = User = mongoose.model("users", UserSchema);
Profile schema:
const ProfileSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "users"
},
name: {
type: String
},
image: {
type: String
},
bio: {
type: String
},
location: {
type: String
},
website: {
type: String
},
social: {
youtube: {
type: String
},
facebook: {
type: String
},
instagram: {
type: String
},
twitter: {
type: String
}
}
});
module.exports = User = mongoose.model("profile", ProfileSchema);
Route:
router.get("/user/:username", (req, res) => {
const errors = {};
Profile.findOne({ user: req.params.user.username })
.populate("user", "username")
.then(profile => {
if (!profile) {
errors.noprofile = "There is no profile for this user";
return res.status(404).json(errors);
}
res.json(profile);
})
.catch(err => res.status(404).json(err));
});
Please try this :
router.get("/user/:username", async (req, res) => {
const errors = {};
try {
const profile = await User.aggregate([
{ $match: { username: req.params.username } },
{ $lookup: { from: "profile", localField: "_id", foreignField: "user", as: "userProfile" } },
{ $project: { userProfile: { $arrayElemAt: ["$userProfile", 0] }, username: 1, _id:0 } }
]).exec();
if (!profile.length) {
errors.noprofile = "There is no profile for this user";
return res.status(404).json(errors);
}
res.json(profile[0]);
} catch (error) {
console.log('Error in retrieving user from DB ::', error);
return res.status(404);
}
})
Try using aggregate, firstly you check-in user table for getting details of a specific username then fetch the profile details as below using lookup, if no profile found after unwind the document will not be fetched and you can check on aggregate result's length as aggregate always return an array in result :
User.aggregate([
{$match:{ username: req.params.user.username }},
{$lookup:{from:"profile",localField:"_id",foreignField:"userId",as:"profileData"}},
{$unwind:"$profileData"},
{$project:{profileData:1,username:1}}
{$limit:1}
])
.then(profile => {
if (!profile.length) {
errors.noprofile = "There is no profile for this user";
return res.status(404).json(errors);
}
res.json(profile[0]);
})
You can do it in 2 steps.
Look for users containing username in userSchema, get it's id.
Then in promise, use that id to, look for profileSchema contains.
router.get("/user/:username", (req, res) => {
users.findOne({ username: req.params.username }).then(_user=>{
profile.findOne({ user: _user._id }).populate('user').then(_profile => {
res.json(_profile);
})
})
});
This code will look for username in userSchema and look for userSchema's id in profileSchema then returns profileSchema populated with user.

Resources