problems to update mongodb collection - javascript

so I have two different collections for my social media app. One for the users and the other one for the user's posts. Whenever I'm updating the info from one of my user's collection it should also modify it on the post (since my post collection includes data from the user too), but it's only doing it on the posts that I create after that and not on the ones that I've been creating before. How can I fix it?
USER SCHEMA
const userSchema = new Schema({
name: { type: String, required: true },
lastname: { type: String, required: true },
username: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true, minlength: 8 },
avatar: { data: Buffer, contentType: String },
});
POST SCHEMA
const postSchema = new Schema({
user: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
name: { type: String, required: true },
lastname: { type: String },
username: { type: String },
avatar: { data: Buffer, contentType: String },
date: { type: Date, default: Date.now() },
textOfThePost: { type: String, required: true },
});
EDIT FUNCTION EXPRESS/MONGOOSE
router.put("/edit_profile", async (req, res) => {
try {
const { name, lastname, username } = req.body;
const user = await User.findById(req.user).select("-password");
if (!user) return res.status(404).json("User doesn't exists");
if (name) user.name = name;
if (lastname) user.lastname = lastname;
if (username) user.username = username;
await user.save();
res.json(user);
} catch (err) {
res.status(500).json({ error: err.message });
}
};

You can use updateMany() for that purpose.
const res = await Post.updateMany({ user: user.id }, { name: user.name, username: user.username /* ... */ });
However as already pointed out you are storing user data redundant on the post model as well as on the user model which is not necessary. Similar to joins in SQL you can simply use populate() and not store any user-related data on your post model. This way everytime you query your posts it will automatically pull the latest matching user model by its id.
myPost.populate('user')
Note that therefore the ref is required, which tells mongoose how to populate the user field.

Related

How to insert data into MongoDB collection?

I'm using NodeJS with Mongoose. I've two tables into db.js:
const mongoose = require('mongoose')
const UserSchema = new mongoose.Schema(
{
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true }
},
{ collection: 'users' }
)
const model = mongoose.model('UserSchema', UserSchema)
const AccountSchema = new mongoose.Schema(
{
username: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'hahaha' },
balance: { type: Number, required: true }
},
{ collection: 'accounts' }
)
module.exports.UserSchema = model
module.exports.AccountSchema = model
As you can see the first collection contains users (username, email, password). The second collection represents a bank account, related to a specific user. So, it has two fields: user (foreign key) and balance ($100, i.e.). First question: is my code correct to accomplish this task?
Second question: how can I insert data into the AccountSchema?
I obviously want to insert data only if the user exists into Userschema. I think that this doesn't work:
const Schema = require('./model/db')
app.post('/api/addaccount', async (req, res) => {
const { username, balance } = req.body
try {
const response = await Schema.AccountSchema.create({
username,
balance
})
console.log('User account successfully: ', response)
res.json({status : "ok"})
} catch (error) {
throw error
}
})
How can I do this?
This won't work. You've to query the User model first to check if any user exists with this username. If yes, you'll continue to store data in the Account model, if not you'll return a response something like user doesn't exist

Can't push items into mongodb arrays

I'm trying to make a simple social media app using react, express and mongodb.
This is the user model:
const UserSchema = new mongoose.Schema(
{
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
email: { type: String, required: true, unique: true},
followers: { type: Array, required: false },
following: { type: Array, required: false },
likes: { type: Array, required: false},
},
{ collection: 'users' }
)
This is the express server:
app.post('/api/follow', async (req, res) => {
const {token, username} = req.body
if (token === null)
{
return res.json({status: 'error'})
}
const user = await User.findOne({username}).lean()
const _visitor = jwt.verify(token, JWT_SECRET)
const visitor = await User.findOne({username: _visitor.username})
if (!user)
{
return res.json({status: 'error', error: 'User not found.'})
}
if (!visitor)
{
return res.json({status: 'error', error: 'User not found.'})
}
visitor.following.push(user._id)
user.followers.push(me._id)
return res.json({status: 'ok'})
})
But when I check the mongodb compass the following and followers arrays are empty.
The best way is to use findOneAndUpdate() method to update a value.
Also, if you are updating from two different collections you can use transactions. This is optional but can be useful to avoid inconsitences in your DB.
So your code can be something similar to this:
const updateVisitor = await User.findOneAndUpdate(
{
username: _visitor.username
},
{
$push:{
following: user._id
}
})
Example here
An the same code for user:
const updateUser = await User.findOneAndUpdate(
{
username: username
},
{
$push:{
followers: me._id
}
})

Mongoose - creating and saving a document, then saving new document with its id

I have a user schema that looks like this:
const userSchema = new Schema({
email: {
type: String,
required: true,
unique: true,
trim: true
},
password: {
type: String,
required: true
},
role: {
type: String,
default: 'customer',
enum: ['customer', 'farmer', 'admin']
},
user_id: {
type: Schema.Types.ObjectId,
required: true,
unique: true
}
})
Additionally, I have another schema that would be called "customer" and looks something like this:
const customerSchema = new Schema({
company: String,
contact: String,
...etc
})
Now what I'd like to do is on creation of the User document, create and save a new Customer document, then save itd _id to my User document's user_id field.
The post request would look something like this:
// POST - USER REGISTRATION
router.post('/register', function (req, res) {
const { email, password, role } = req.body
const user = new User({ email, password, role,
user_id: new Customer({
company: req.body.company,
contact: req.body.contact,
...etc (rest of data)
})})
user.save(function(err) {
if (err) {
res.status(500)
.send("Failed to register. Please try again.")
}
else {
res.status(200).send("Registered.")
}
})
})
While this seems to create a Customer object (there's an ObjectID under user_id), the customer isn't saved to the database (naturally since .save isn't called).
My original approach here was to have a user_id variable set to null, then have customer create & save itself, then set the user_id variable to the customer._id value, but this didn't work as user.save(func(err)) would have a "null" user_id value.
just try like this
router.post("/register", async function (req, res) {
try {
const { email, password, role } = req.body;
let customer = new Customer({
company: req.body.company,
contact: req.body.contact,
});
let resultCustomer = await customer.save();
const user = new User({
email,
password,
role,
user_id: resultCustomer._id,
});
await user.save();
res.status(200).send("Registered.");
} catch (error) {
res.status(500).send("Failed to register. Please try again.");
}
});

Mongoose - How to update all objects within an array in MongoDB?

I am creating an app where I want to toggle the default address of a person.
My User Schema contains a field which is an array of delivery addresses which are objects.
One of the fields is isDefault, which is the defaultAddress field I want to toggle from true to false and vice versa.
Specifically, if the user changes their default address, I want to set the rest of the addresses to false and update the one he/she chose to be true
User Schema
const UserSchema = Schema({
email: {
type: String,
required: true,
},
deliveryAddresses: [deliverySchema]
Delivery Address Schema
{
id: {
type: Schema.Types.ObjectId,
required: true
},
isDefault: {
type: Boolean,
required: true,
default: false,
},
name: {
type: String,
},
email: {
type: String,
},
phone: {
type: String,
},
}
To do that, what I have done so far is:
Getting the email of the user.
Getting the id of the delivery address from the user that will be toggled to true.
exports.setDefault = (req, res, next) => {
const email = req.body.email;
const id = req.body.id;
User.findOne({ email: email })
.then((user) => {
let addresses = [...user.deliveryAddresses];
addresses.forEach((address) => {
address.isDefault = false;
});
const index = addresses.findIndex((address)=> {
return address.id.toString() === id.toString();
});
addresses[index].isDefault = true;
user.deliveryAddresses = addresses;
return user.save();
})
.then((doc) => {
res.status(200).json({
user: doc,
statusCode: "200",
msg: "Address updated successfully",
});
})
.catch((err) => {
res.status(500).json({
statusCode: 500,
error: err,
msg: "Something went wrong",
});
});
};
However, after doing all this, on testing my api on postman, it seems to work, no errors.
But on checking the database, nothing has changed.
I am at loss as to what I'm doing wrong.
Mongoose is weird. You need to mark the deliveryAddresses sub-object as modified, otherwise its changes won't be saved.
user.markModified('deliveryAddresses');
user.save();
From Mongoose FAQs
"Mongoose doesn't create getters/setters for array indexes; without
them mongoose never gets notified of the change and so doesn't know to
persist the new value. There are two workarounds: MongooseArray#set or
Document#markModified()."
Can you try sth like
user.markModified('deliveryAddresses');
user.save();
More on https://mongoosejs.com/docs/faq.html

Node get the first element in array of object

I'm trying to do some relations between my schemas and I have some problems with my solution.
user schema:
let userSchema = new mongoose.Schema({
username: { type:String, default:null },
gender: { type:String, default:null },
role: { type: mongoose.Schema.Types.ObjectId, ref: 'Role', required: true },
});
role schema:
let roleSchema = new mongoose.Schema({
name: { type:String, default:"Player" },
privileges:
[
{
resource: String ,
actions: [ String ]
},
],
});
and my query is
User.find({ "email":email }).populate({path: 'role', model: 'Role'}).limit(1).exec().
then(results => {
if (results.length) {
user = results[0];
console.log(user.role.privileges);
}
else {
throw new APIError("login_failed");
}
})
I need to access to the first element of privileges and Thank you.
The first parameter returned by Mongoose (and Node in general) is not your data. It's the error (if any). You need to write then( (error, results) => {
I need to access to the first element of privileges
privileges being an array, simply access the first element using :
user.role.privileges[0]
As an aside, you can also use Mongoose's .findOne() method, instead of .find().limit(1) :
User
.findOne({ email }) // Shorthand for { email : email }
.populate({path: 'role', model: 'Role'})
.exec()
.then( (error, user) => {
if(error || !user) throw new APIError("login_failed");
console.log(user.role.privileges[0]);
})

Categories

Resources