How to insert data into MongoDB collection? - javascript

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

Related

MongoDB concatenate for dictionary key

I am trying to update a dictionary field in MongoDB. But I can't figure out a way to update nested dictionary with a variable as key.
Here is the schema
const UserSchema = new mongoose.Schema({
email: String,
password: {type: String, unique: true, required: true},
id: mongoose.Schema.Types.ObjectId,
course: mongoose.Schema.Types.Mixed
});
I am trying to update course so that every time a course name is added as a key in the following form, with course name stored in the variable addName
For example, if addName = Intro to Computer Science, the desired result would be
{
"email" 12345#gmail.com,
...
"course": {
"Intro to Computer Science" {
"syllabus": ""
}
}
}
However, I am not sure how to add a variable key to the dictionary. When I tried below, but I get the following syntax error
app.post("/api/add-course/", (req, res) => {
const email = req.body.email;
const addName = req.body.addName;
console.log(req.body)// assumes that User was registered in `./db.mjs`
User.updateOne({"email": email}, {'$set': {'course.'+addName: {"syllabus": ""}}},
).then(result => {
res.status(201).json({
message: "success",
course: user.course
})
}).catch(err => {
console.log(err),
res.status(500).json({
error: err
});
});
console.log(user);
})

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.");
}
});

problems to update mongodb collection

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.

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