I am using Express node, MongoDB In this App.
Idea: send Post request contains an array of objects, => check if any object is existed before, => add the
not existed elements to the array in the document in one shot.
problem: Each time I sent a post request only one element is added. I have to repeat 3 times in order to add an array of 3 elements.
solution tried: before I used promise.all() nothing has been added. after I used promise.all only one element is added
code:
.post(cors.corsWithOptions, authenticate.verifyUser, (req, res, next) => {
let favstoAdd = req.body.favorites;
let user = req.user;
//check if the user have a favorites already and create favorites if it is not existed
var p1 = Favorites.findOne({ user: user._id })
.then((res_user) => {
if (res_user !== null) {
}
else {
Favorites.create({ user: user._id, favorites: [] });
}
});
//check if the dish Existed before in the favs and add them to the new filtered array
var altered_favstoAdd = [];
var p2 = favstoAdd.map((fav) => {
Favorites.findOne({ favorites: fav._id })
.then((dish) => {
if (dish == null) {
altered_favstoAdd.push(fav);
}
})
.catch((err) => { next(err) });
});
var p3 = promise.all([p1, p2]).then(values => {
//update favorite
for (let i = 0; i < altered_favstoAdd.length; i++) {
let alt_fav = altered_favstoAdd[i];
Favorites.update({ user: user._id }, { $push: { favorites: alt_fav } }, { new: true }, (err, resp) => {
if (err) { next(err); }
})
}
});
//respond with the favorite item
promise.all([p3]).then(
Favorites.findOne({ user: user._id })
.then((favorite) => { res.json(favorite); })
.catch((err) => { next(err) })
)
})
I think the problem is in the map function :
var p2 = favstoAdd.map((fav) => {
Favorites.findOne({ favorites: fav._id })
.then((dish) => {
if (dish == null) {
altered_favstoAdd.push(fav);
}
})
.catch((err) => { next(err) });
});
this function does not itereate over the whole array some thing is preventing it.
any Ideas??
Related
The following code works great to retrieve all the items in the collection. However, the uids are not available here and I need them to be able to compare with other userRefs.
app.get("/api/all-users", (req, res) => {
let arr = [], i = 0;
db.collection('users').get()
.then((result) => {
result.forEach((doc) => {
arr[i] = doc.data();
i++
})
res.json(arr);
})
.catch((err) => {
res.json(err);
})
})
This returns a json response:
users: [
{name: 'Name', username: 'Username' etc ..}
]
However I was looking for something with the actual uids. How would I get that information with a query like this?
Assuming you mean the document ID where you say uid (which is typically used to denote a user ID).
Since you only return doc.data() you are dropping the document ID. If you want to return both, you could do:
app.get("/api/all-users", (req, res) => {
let arr = [], i = 0;
db.collection('users').get()
.then((result) => {
result.forEach((doc) => {
arr[i] = { ...doc.data(), id: doc.id };
i++
})
res.json(arr);
})
.catch((err) => {
res.json(err);
})
})
Or a simpler version of the same:
db.collection('users').get()
.then((result) => {
res.json(result.docs.map(doc => {
return { ...doc.data(), id: doc.id }
});
})
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
I have wrote a simple Update function. Its working fine for some minutes and then again its not working. Where I am going wrong? Please help me. I use PUT as my method.
code
accept = (req, res) => {
this._model.update({
user: new mongoose.Types.ObjectId(req.params.uid)
}, {
$set: {
status: 'active'
}
}, (err, obj) => {
if (err || !obj) {
res.send(err);
} else {
res.send(obj);
}
});
}
Model
{
"_id":"5d3189a00789e24a23438a0d",
"status":"pending",
"user":ObjectId("5d3189a00789e24a23438a0d"),
"code":"CT-123-345-234-233-423344",
"created_Date":"2019-07-19T09:13:04.297Z",
"updated_Date":"2019-07-19T09:13:04.297Z",
"__v":0
}
Request
api.abc.com/api/accept/5d3189a00789e24a23438a0d
Sometime it is returing values and sometime null.
You can use the following code to ensure the model is tied to a connection. This could be an issue of connection to the database.
const config = require('./config');
console.log('config.database.url', config.database.url);
return mongoose.createConnection(config.database.url, {
useMongoClient: true
})
.then((connection) => {
// associate model with connection
User = connection.model('User', UserSchema);
const user = new User({
email: 'someuser#somedomain.com',
password: 'xxxxx'
});
const prom = user.update();
// Displays: 'promise: Promise { <pending> }'
console.log('promise:', prom);
return prom
.then((result) => {
// Don't see this output
console.log('result:', result);
})
.catch((error) => {
// Don't see this output either
console.log('error:', error);
});
})
.catch((error) => {
console.log(error);
});
I think you need to use promise or async/await, try this
accept = async (req, res) => {
try {
const result = await this._model.update({
user: new mongoose.Types.ObjectId(req.params.uid)
}, {
$set: {
status: 'active'
}
});
return res.send(result);
} catch (e) {
return res.send(e);
}
};
Suppose that we have a shopping cart in the site, we have specified number of a good in database. Whenever the user wants to validate his/her cart and finalize it, I want to subtract the number of goods that the user purchased from total count of the product. How can I do that?
router.post('/done', (req, res) => {
// substract from the count
for (var i = 0; i < req.body.cart.length; i++){
Product.findOne({_id: req.body.cart[i]._id}).exec((err, result) => {
result.count = result.count - req.body.cart[i].count;
// update the value of result.count and save it on database
})
}
})
You just need to save, and also check for errors.
router.post('/done', (req, res) => {
// substract from the count
for (var i = 0; i < req.body.cart.length; i++){
Product.findOne({_id: req.body.cart[i]._id}).exec((err, result) => {
if(result)
{
result.count = result.count - req.body.cart[i].count;
result.save((err) => {
if (err) // do something
});
}
//If you don't find the product for some reason, do something
})
}
})
You can use mongoose's findOneAndUpdate() and $inc reference operator with a negative value to decrement the count.
Docs
The following update() operation uses the $inc operator to decrease the quantity field by 2 (i.e. increase by -2) and increase the "metrics.orders" field by 1:
db.products.update(
{ sku: "abc123" },
{ $inc: { quantity: -2, "metrics.orders": 1 } }
)
Making those changes
'use strict';
router.post('/done', (req, res) => {
let {cart} = req.body;
if (!Array.isArray(cart) || cart.length === 0) {
return res.status(400).send({
msg: 'Empty cart'
});
}
let updates = cart.map(item => {
return Product.findOneAndUpdate({
_id: item._id
}, {
$inc: {
count: -1 * item.count
}
}, {
upsert: false
});
});
Promise.all(updates).then(() => {
return res.status(200).send({
msg: 'inventory updated'
});
}).catch(err => {
console.log('err', err.stack);
return res.status(500).send({
msg: 'inventory update failed!'
});
});
});
In my application, I have an Model say it is Record, and a Record may have several Attachment which can be uploaded to the server.
Generally, when creating a Record with Attachment(files), I will upload and save the files first, then save the record, like this:
function createOrUpdateInfo(req, res, next) {
var record = req.body;
var attachmentIds = (record.files || []).map(function (a) {
return a.id;
});
var attachmentFilter = {
where: {
id: {
$in: attachmentIds || []
}
}
};
DB.sequelize.transaction(function (t) {
var pro;
if (record.id) {
//update
//update the basic information first
return Record.update(record, {
where: {
id: req.params.id
}, transaction: t
}).then(function (num, infos) {
//find the record just saved.
return Record.findById(req.params.id).then(function (record) {
//find the attachmens which have been saved
return Attachment.findAll(attachmentFilter).then(function (atts) {
//update the record, create the association.
return record.setFiles(atts, {transaction: t});
});
})
});
} else {
//save
return Record.create(record, {transaction: t}).then(function (record) {
return Attachment.findAll(attachmentFilter).then(function (atts) {
return record.setFiles(atts, {transaction: t});
});
});
}
}).then(function (result) {
Util.sendJson(res, result)
}).catch(function (err) {
next({message: err.message, code: 500});
});
}
As shown, there are too many nested callbacks when create or update a Record.
Is this can be fixed?
I've reorganized your code a bit. Hope it helps.
function createOrUpdateInfo(req, res, next) {
var record = req.body;
var attachmentIds = (record.files || []).map(function (a) {
return a.id;
});
var attachmentFilter = {
where: {
id: {
$in: attachmentIds || []
}
}
};
DB.sequelize.transaction(function (t) {
var pro;
return (function () {
if (record.id) {
//update
//update the basic information first
return Record.update(record, {
where: {
id: req.params.id
}, transaction: t
}).then(function (num, infos) {
//find the record just saved.
return Record.findById(req.params.id);
});
} else {
//save
return Record.create(record, {transaction: t});
}
}()).then(function () {
//find the attachmens which have been saved
return Attachment.findAll(attachmentFilter);
}).then(function (atts) {
//update the record, create the association.
return record.setFiles(atts, {transaction: t});
});
}).then(function (result) {
Util.sendJson(res, result)
}).catch(function (err) {
next({message: err.message, code: 500});
});
}