NodeJs, MongoDb - Why is my code duplicating documents instead of updating them? - node.js

I want to find an existing document in MongoDB by its _id. Everything works except trying to edit existing just creates a new document with a new _id instead of updating the current. It seems that it skips if (this._id) { in the model file. Very frustrated because I can see the issue but cannot find a fix. Thanks in advance!
plant.js controller:
exports.getEditPlant = (req, res, next) => {
const editMode = req.query.edit;
if (!editMode) {
console.log('Not Edit Mode');
}
const dbId = req.params._id;
Plant.findById(dbId)
.then(plant => {
if (!plant) {
console.log('Err');
res.redirect('back');
}
res.render('account/edit-plant', {
pageTitle: 'Edit Plant',
path: '/account',
plant: plant,
edit: editMode
});
}).catch(err => {
console.log(err);
});
};
exports.postEditPlant = (req, res, next) => {
const updatedName = req.body.common_name;
const scientific_name = req.body.scientific_name;
const updatedImg = req.body.image_url;
const slug = req.body.slug;
const updatedPlant = new Plant(updatedName, scientific_name, updatedImg, slug, new ObjectId(id));
updatedPlant.addMyPlant()
.then(plant => {
res.redirect('home');
}).catch(err => {
console.log(err);
})
};
plant.js model:
const mongodb = require('mongodb');
const getDB = require('../util/database').getDB;
module.exports = class Plant {
constructor(common_name, scientific_name, image_url, slug, id) {
this.common_name = common_name;
this.scientific_name = scientific_name;
this.image_url = image_url;
this.slug = slug;
this._id = id;
}
addMyPlant() {
const db = getDB();
let dbOp;
if (this._id) {
dbOp = db
.collection('myplants')
.updateOne({ _id: new mongodb.ObjectId(this._id) }, { $set: this });
} else {
dbOp = db.collection('myplants').insertOne(this);
}
return dbOp
.then(result => {
})
.catch(err => {
console.log(err);
});
}
static getMyPlants() {
const db = getDB();
return db.collection('myplants')
.find().toArray()
.then(plants => {
return plants;
}).catch(err => {
console.log(err);
});
}
static findById(dbId) {
const db = getDB();
return db
.collection('myplants')
.find({ _id: new mongodb.ObjectId(dbId) })
.next()
.then(plant => {
return plant;
})
.catch(err => {
console.log(err);
});
}
}

You need to assign the known _id to the ObjectID outside of the query.
In your code, you instantiate a new ObjectID inside your query but the value you passed in is not found.
This is a simplified version of your class with tests:
const mongodb = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
const url = "mongodb://localhost:27017/mydb";
class Plant {
constructor(name) {
this.name = name;
}
// this method pulls all the records for me to test results
getAll() {
mongodb.connect(url, { useUnifiedTopology: true }, (err, db) => {
if (err) throw err;
var dbo = db.db("mydb");
dbo.collection("plants").find({}).toArray(function (err, result) {
if (err) console.log(err);
console.log(result);
db.close();
});
})
}
// update single record
updateMyPlant() {
mongodb.connect(url, { useUnifiedTopology: true }, (err, db) => {
if (err) console.log(err);
console.log("Mongo connected...");
const dbo = db.db("mydb");
// if you know the _id
// instantiate a variable outside your query
// now const id is the same as the _id you wants to query
const id = ObjectID("5fd8a1100617b03d8c737da0");
const myquery = { "_id": id };
const newvalues = { $set: { "name": "Marlon Brando" }};
try {
dbo.collection("plants").updateOne(myquery, newvalues, (err, res) => {
if (err) console.log(err);
console.log("update result", res.result, res.upsertedId);
db.close();
})
}
catch (e) {
console.log(e);
}
})
}
}
// test
const plant = new Plant("Alexa");
plant.updateMyPlant();
plant.getAll();
module.exports = Plant;
/**
* Logs:
* Mongo connected...
update result {
n: 1,
nModified: 1,
ok: 1
}
null
[{
_id: 5 fd8a1100617b03d8c737da0,
name: 'Marlon Mickey',
scientific_name: 'Brittain'
}]
*/
As you can see the _id is retained while the properties you want to change are updated.
See more info about ObjectID here

Related

How to populate an id in an array of objects firebase

committeeHead is a reference in collection users. I want to populate this id to get the specific data.
tried using Promise.all but I don't completely understand it and it isn't working for me.
const getAllCommittees = async (req, res, next) => {
try {
const committees = await db.collection("committees").get();
const committeesArray = [];
committees.forEach((doc) => {
committeesArray.push({ id: doc.id, ...doc.data() });
});
const committeesWithUsers = await Promise.all(
committeesArray.map((committee) => {
const user = db.collection("users").doc(committee.committeeHead).get();
return {
committee,
user,
};
})
);
res.json(committeesWithUsers);
} catch (err) {
console.log(err);
next(err);
}
};

how do i use find() with mongoose to find by another field

I am trying to find subscriptions by MovieId,or MembeId
this is the schema:
const SubscriptionSchema = new mongoose.Schema({
MovieId : String,
MemberId : String,
Date : Date
})
this is the server:
BL:
const getAllSubscriptionsByMovieId = function(movieid)
{
return new Promise((resolve,reject) =>
{
Subscription.find({MovieId : movieid}, function(err, data)
{
if(err)
{
reject(err)
}
else
{
resolve(data);
}
})
})
}
router:
router.route('/')
.get( async function(req,resp)
{
let data = await subscriptionsBL.getAllSubscriptionsByMovieId(movieid)
return resp.json(data);
})
what is wrong??

Check if user exists in router before creation in database with Sequelize

I have a function to check if a user exists, and a function to create a new user in my User model.
What I want to do is call them in the router to check if a user with the email adress in req.body already exists.
If it does, I want to return a message, and if not, I want to create the user.
When I try to call the route in Postman, I get this error in node console :
node_modules/express/lib/response.js:257
var escape = app.get('json escape')
TypeError: Cannot read properties of undefined (reading 'get')
User model :
const Sequelize = require("sequelize");
const connexion = require("../database");
const User = connexion.define(
"users",
{
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
email: {
type: Sequelize.STRING(100),
allowNull: false,
},
password: {
type: Sequelize.STRING(100),
allowNull: false,
},
},
{
freezeTableName: true
}
);
function checkUser(userEmail) {
const findUser = User.findOne({ where: { userEmail } }).catch((err) => {
console.log(err);
});
if (findUser) {
return res.json({ message: "Cette adresse email est déjà enregistrée" });
} else {
return false;
}
}
function createUser(userData) {
console.log(userData);
User.create(userData)
.then((user) => {
console.log(user);
})
.catch((err) => {
console.log(err);
});
}
module.exports = { createUser, checkUser };
user controller :
const createUser = require("../models/User");
const bcrypt = require("bcrypt");
const saltRounds = 10;
addUser = async (req, res) => {
try {
const userData = req.body;
console.log(req.body);
bcrypt.hash(userData.password, saltRounds, async function (err, hash) {
userData.password = hash;
const newUser = await createUser(req.body);
res.status(201).json({ newUser });
});
} catch (err) {
console.log(err);
res.status(500).json("Server error");
}
};
module.exports = addUser;
user router :
const express = require("express");
const router = express.Router();
const addUser = require("../controllers/userController");
const { checkUser } = require("../models/User");
router.post("/", async (req, res) => {
const { email } = req.body;
const alreadyExists = await checkUser(email);
if (!alreadyExists) {
addUser(req.body);
}
});
module.exports = router;
EDIT : Finally I'm trying a more simple way. I will do the check part directly into the createUser function.
But now, it creates the user even if the email already exists ^^
async function createUser(userData) {
console.log(userData);
const findUser = await User.findOne({ where: userData.email }).catch(
(err) => {
console.log(err);
}
);
findUser
? console.log(findUser)
: User.create(userData)
.then((user) => {
console.log(user);
})
.catch((err) => {
console.log(err);
});
}
i think the problem is with this part you are trying to use res but it doesn't exist in your checkUser function
if (findUser) {
return res.json({ message: "Cette adresse email est déjà enregistrée" });
} else {
return false;
}
try this instead
if (findUser) {
return true });
} else {
return false;
}
UPDATE to fix the problem of user creation if it already exists
async function createUser(userData) {
console.log(userData);
const findUser = await User.findOne({ where: userData.email }).catch(
(err) => {
console.log(err);
}
);
if(!findUser){
findUser
? console.log(findUser)
: User.create(userData)
.then((user) => {
console.log(user);
})
.catch((err) => {
console.log(err);
});
}
}
Problem solved by doing this (thanks super sub for your help):
async function createUser(userData) {
console.log(userData);
const email = userData.email;
const findUser = await User.findOne({ where: { email } }).catch((err) => {
console.log(err);
});
if (!findUser) {
User.create(userData)
.then((user) => {
console.log(user);
})
.catch((err) => {
console.log(err);
});
}
}

How to add to array in mongo db collection

Good evening,
I have my model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const widgetSchema = new Schema({
city: {
type: String
}
})
const userSchema = new Schema({
name: {
type: String,
},
password: {
type: String
},
widgets: [widgetSchema]
})
const User = mongoose.model('user', userSchema);
module.exports = User;
And my question is how can I add elements to the widget array?
Should I use an update or what?
I think, firstly I need to find user document:
app.post('/addwidget', async (req, res) => {
const { city } = req.body;
try {
const user = await User.findOne({"name": "1"});
}
catch(err){
console.log(err)
}
})
and thank what? Is there method like push or something like that?
Try this one :
try {
const user = await Research.findOneAndUpdate({ name: '1' }, { $push: { widgets: { city: 'viking' }} })
if (user) return user;
else return false;
} catch (error) {
console.log(error);
}
you can use $push or $addToSet to add new item to the widgets array :
app.post('/addwidget', async (req, res) => {
const { city } = req.body; //
try {
const user = await User.findOneAndUpdate({"name": "1"} , { $push: { widgets: city }});
}
catch(err){
console.log(err)
}
})
or :
app.post('/addwidget', async (req, res) => {
const { city } = req.body;
try {
const user = await User.findOneAndUpdate({"name": "1"} , { $addToSet : {widgets: city }});
}
catch(err){
console.log(err)
}
})
From the doc: Adding Subdocs to Arrays, you can use MongooseArray.prototype.push()
E.g.
app.post('/addwidget', async (req, res) => {
const { city } = req.body;
try {
const user = await User.findOne({ name: '1' });
user.widgets.push({ city: 'viking' });
await user.save();
} catch (err) {
console.log(err);
}
});

how can i get properties as well as its method of a class on node.js

I am new on Node.js. Here I created a user model with some method like save, addToCart, findById and so on.
Here is my User Model
const getDb = require('../util/database').getDb;
const mongoDb = require('mongodb');
const objectId = mongoDb.ObjectID;
module.exports = class User {
constructor (username, email, cart, id){
this.username = username;
this.email = email;
this.cart = cart; // {items : []}
this._id = id;
}
save(){
const db = getDb();
return db.collection('users').insertOne(this)
.then(result => {
console.log("User Created Succesfully");
})
.catch(err => {
console.log(err);
})
}
addToCart(product){
const updateCart = { items : [{productId: new objectId(product._id), quantity : 1}]};
const db = getDb();
return db.collection('users')
.updateOne({_id: new objectId(this._id)}, {$set: {cart: updateCart } })
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
})
}
static findById(userId){
const db = getDb();
return db.collection('users').find({_id: new objectId(userId)}).next();
}
}
at the beginning i am creating a req.user by following method:
app.use((req,res,next) => {
User.findById('5de9f4f7f099c426505c0c9e')
.then(user => {
console.log(user);
req.user = new User(user.username,user.email, user.cart, user._id);
next();
})
.catch(err => {
console.log(err);
});
});
Still, there is all ok I got req.user but when I am trying to call a method of user model from another script I couldn't access the method addToCart of User model.
Here is the code where I am calling the user method
exports.postCart = (req, res, next) => {
const prodId = req.body.productId;
Product.findById(prodId, product => {
console.log(req.user);
return req.user.addToCart(product);
})
.then(result => {
console.log("Shop",result);
})
.catch(err => {
console.log(err);
})
//res.redirect('/cart');
}
There is no error at console. But, cart properties is not getting updated. How can I make this possible?

Resources