Update Mongo document in promise after save with _id - node.js

What I want to do:
Send POST request
Save document into mongoDB database
Get it's newly created _id
Use _id as parameter to find and update document
Write id as parameter in string route like /api/page/screen/${id}
Problem:
Document is not updated. Console.log return Screen updated null.
What I have done:
First I make a Promise function which is called on POST request. It is saving new document.
Next I call .then where I do findByIdAndUpdate using id returned from resolved promise.
In result I have newly created document, but update is not done.
// controller.js
const mongoose = require('mongoose');
app.route('/api/page/scan').post(search_a_page)
const search_a_page = async (req, res) => {
const metric = new Metric(payload);
const saveMetric = new Promise((resolve, reject) => {
metric.save((err, document) => {
if (err) res.send(err);
res.json(document);
const id = document._id.toString(); // make string from ObjectId
if (err) reject(new Error({msg: 'It does not work'}));
resolve({msg: 'Metric saved!', id: id});
})
});
saveMetric.then((id) => {
Metric.findByIdAndUpdate(mongoose.ObjectId(id), // string to ObjectId
{"screen_url": `/api/page/screen/${id}`}, (err, result) => {
if (err) {console.log(err);}
else {console.log('Screen updated', result)} // got "Screen updated null"
})
id is taken form mongoDB auto-generated _id
// model.js
const mSchema = new Schema({
_id: Schema.Types.ObjectId,
url: String,
date: Number,
screen: String,
});
const Metric = mongoose.model('Metric', mSchema);
Is it a problem with converting ObjectId to String / String to ObjectId or something else?
UPDATE - solved
According to article we can use .save to update document. That method solved the problem.
When first .save is resolved I used method .then and made update directly accessing document screen property and assigning new value.
saveMetric.then((data) => {
metric.screen = `/api/page/screen/${data.id.toString()}`;
metric.save((err, document) => {
if (err) res.send(err);
console.log(document)
})
});

Related

node.js and mongodb increment _id sequentially in existing database

Good morning everyone.
So I'm doing a class assignment wherein I'm connecting to an existing mongoDB database (via a node.js server), and I'm adding a bunch of data to it from a form on an HTML site. I've got the form information adding correctly, but there's two fields server side that aren't responding to new data. There is the primary key (_id) which instead of incrementing from the current last number, get's incremented by ObjectId('longnumericvale'), and CustomerID which get's populated by an undefined value. The last record existing in the database has both _id and CustomerId as the same number. How can I get node.js to look at this number and auto increment it when it's adding my form data as a new document in the mongodb DB. Code below:
app.post("/orderform", (req, res) => { //This takes post action from html and stores it
console.log("successfully posted")
var item = {
CustFirstName: req.body.CustFirstName,
CustLastName: req.body.CustLastName,
CustAddress: req.body.CustAddress,
CustCity: req.body.CustCity,
CustProv: req.body.CustProv,
CustPostal: req.body.CustPostal,
CustCountry: req.body.CustCountry,
CustHomePhone: req.body.CustHomePhone,
CustBusPhone: req.body.CustBusPhone,
CustEmail: req.body.CustEmail,
userid: req.body.userid,
passwd: req.body.passwd,
};
console.log("Customer information stored as:");//this is just a debug to the console to make sure it's grabbing the info
console.log(item);
//here we connect to the datbase, and insert every item above to its corresponding position in the "customers" collection of "travelexperts" database
mongo.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true },
(err, client) => {
if (err) throw err;
//select database
const db = client.db("travelexperts");
//grab a collection
const collection = db.collection("customers");
collection.insertOne(item, (err, res) => {
if (err) throw err;
console.log("Items inserted");
db.close;
});
});//endconnection
res.redirect('/thanks');
console.log("finished, redirected")
});
//render thank you page for after submitting order
app.get('/thanks', (req, res) =>{
res.render("thanks");
});
I've read the documentation for mongodb on autoincrementing, but it's a bit beyond me how to implement it in my specific example.
UPDATE
So maybe I didn't explain the problem really well. I'm trying to log into two separate collections now, and I have that working. with this code below:
app.post("/orderform", (req, res) => { //This takes post action from Order.html form and stores all form inputs with corresponding names in a variable called item
console.log("successfully posted")
var item = {
CustFirstName: req.body.CustFirstName,
CustLastName: req.body.CustLastName,
CustAddress: req.body.CustAddress,
CustCity: req.body.CustCity,
CustProv: req.body.CustProv,
CustPostal: req.body.CustPostal,
CustCountry: req.body.CustCountry,
CustHomePhone: req.body.CustHomePhone,
CustBusPhone: req.body.CustBusPhone,
CustEmail: req.body.CustEmail,
userid: req.body.userid,
passwd: req.body.passwd,
};
console.log("This should be an array of all entered customer info:");//this is just a debug to the console to make sure it's grabbing the info
console.log(item);
var book = {
BookingId: "",
BookingDate: new Date(),
BookingNo: "",
TravelerCount:"",
CustomerId: "",
TripTypeId:"",
PackageId: Number(req.query.packId),
};
console.log(book);
//here we connect to the datbase, and insert every item/booking above to its corresponding position in the "customers" collection of "travelexperts" database
mongo.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true },
(err, client) => {
if (err) throw err;
const db = client.db("travelexperts");
const collection = db.collection("customers");
const booking = db.collection("bookings");
collection.insertOne(item, (err, res) => {
if (err) throw err;
console.log("Items inserted");
});
booking.insertOne(book, (err, res) => {
if (err) throw err;
console.log("Items inserted");
});
db.close;
});//endconnection
res.redirect('/thanks');
console.log("finished, redirected")
});
So the issue is that for both collections and bookings, they have incomplete records. collections is 26 documents long, and the last _id is 144. So that's why I need to read that _id and increment it +1 for each new record. There's an _id field for each collection and then a customerId and BookinbId that should match it. Really appreciate all the help so far, but neither of these solutions seems to work. I tried both just before the collections.insertone line, and i tried console logging them and they just return [object Object] in the console instead of the _id value.
To insert a custom ID field for your documents, you should append the _id field with your item object.
The simplest wayc can be to create a global id_counter variable that you increment everytime you execute the /orderform API.
let idCounter = 1;
.
.
.
const itemDoc = {_id: idCounter++, ...item}
collection.insertOne(itemDoc, (err, res) => {
if (err) throw err;
console.log("Items inserted");
db.close;
});
.
.
.
You could also fetch the last inserted Item's id and simply increment it and it could save a lot of effort to keep the ids of the documents in sync incase the server restarts or something.
In that case, you could do something as below using collection.countDocuments() method:
let docLength = 0 // global variable
.
.
.
// inside your api endpoint controller...
collection.countDocuments({}, {}, (err, res)=> {
docLength = res;
})
const itemDoc = {_id: docLength++, ...item}
collection.insertOne(itemDoc, (err, res) => {
if (err) throw err;
console.log("Items inserted");
db.close;
});

MongoDB CRUD routes returning null or wrong values

I've recently started using the MEAN stack and stumbled upon some errors while trying to work with my MongoDB database. I connected to the database successfully, implemented my CRUD routes, and I get wrong values for anything besides the find() method (which returns all the documents in my collection without any problem). The findOne() looks like this for example:
router.route(server.get("/company/:id", (request, response) => {
const companyId = request.params.id;
console.log("Showing company with id: " + companyId)
dbCollection.findOne({ _id: mongodb.ObjectId(companyId) }, (error, result) => {
if (error) throw error;
// return company
response.json(result);
});
}));
The result after making a get request via Postman is null
The insertOne() looks like this:
router.route(server.post("/company/add", (request, response) => {
const company = request.body;
dbCollection.insertOne(company, (error, result) => {
if (error) throw error;
// return updated list
dbCollection.find().toArray((_error, _result) => {
if (_error) throw _error;
response.json(_result);
});
});
}));
It adds one document to the database with the ID that it creates for itself, but for some reason it doesn't take in the body data (2 string elements { "name": "xy", "type": "company" })
And last but not least, the deleteOne():
router.route(server.delete("/company/delete/:id", (req, res) => {
const companyId = req.param.id;
console.log("Delete company with id: ", companyId);
dbCollection.deleteOne({ _id: mongodb.ObjectId(companyId) }, function(err, result) {
if (err) throw err;
// send back entire updated list after successful request (optional)
dbCollection.find().toArray(function(_err, _result) {
if (_err) throw _err;
res.json(_result);
});
});
}));
For some reason it deletes the very first document in the collection, but not the one that is entered with the corresponding ID.
If anyone could help me out with this it would be awesome. Thank you in advance!
Edit 1:
Adding a new document to the collection via Postman
Collection after the add
Edit 2:
Get request via ID and response (returns null)
Console output:
Showing company with id: 5e63db861dd0ce2418ce423d
Edit 3:
Corrected the code for the findOne() and deleteOne() methods.
When you try with _id you need to convert the string(request.params.id) to ObjectId().
Convert string to ObjectID in MongoDB - whoami

How to update/insert an other document in cloud firestore on receiving a create event for a collection using functions

Let us assume that we have two collections say "users" and "usersList"
Upon creating a new user document in users collection with following object
{username: Suren, age:31}
The function should read the above data and update other collection i.e. "usersList" with the username alone like below
{username: Suren}
Let me know the possibility
The code I have tried is
exports.userCreated =
functions.firestore.document('users/{userId}').onCreate((event) => {
const post = event.data.data();
return event.data.ref.set(post, {merge: true});
})
I have done it using below code
exports.userCreated = functions.firestore.document('users/{userId}')
.onCreate((event) => {
const firestore = admin.firestore()
return firestore.collection('usersList').doc('yourDocID').update({
name:'username',
}).then(() => {
// Document updated successfully.
console.log("Doc updated successfully");
});
})
If all you want to do is strip the age property from the document, you can do it like this:
exports.userCreated = functions.firestore.document('users/{userId}').onCreate((event) => {
const post = event.data.data();
delete post.age;
return event.data.ref.set(post);
})

Modifying array directly in mongoose doesn´t works

I have a mongoose schema with a field array.
I need to set the array field directly without get rid off the existent values.
I am using
item.files.concat(myfiles);
in the next code, but it doesn´t work. Only the last item from array is saved
//code
var files=['file1','file2','file3']
var myfiles=[]
files.forEach(function(file){
myfiles.push({title:file});
}
});
//router
FileSchema.findById(id).exec( (err,item) => {
//fill files -- error is here
item.files.concat(myfiles);
item.save(function (err, data) {
if (err) {
return res.status(500).send(err)
}
res.send(data); //send response
})
})
//schema
const mongoose=require('mongoose');
const fileSchema = new mongoose.Schema({
id: {type: Number, unique:true},
...
...
files:[{title:{type: String}}]
});
From MDN web docs:
The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.
item.files = item.files.concat(myfiles);

Mongoose not persisting returned object

Mongo: 3.2.1.
I have a model defined as such:
var MySchema = new Schema(
{
....
records: {type: Array, "default": []};
I first create an object based on that schema with no record field and it's correctly added to the database. I then update that object as such:
Client
angular.extend(this.object.records, [{test: 'test'}]);
this.Service.update(this.object);
Server (omitting the none-problematic code)
function saveUpdates(updates) {
return function(entity) {
var updated = _.merge(entity, updates);
return updated.save()
.then(updated => {
console.log(updated);
Model.find({_id: updated._id}).then((data)=> console.log(data));
return updated;
});
};
}
The first console.log prints the object with records field updated. The second prints the object without. What am I missing? How can the resolved promise be different than the persisted object? Shouldn't data and updated be identical?
I think you have a couple problems.
You are using the variable 'updated' twice.
var updated = _.merge(entity, updates); // declared here
return updated.save()
.then(updated => { // trying to re-declare here
The other issue might be that you are trying to merge the 'updates' property with the mongo object and not the actual object values. Try calling .toObject() on your mongo object to get the data.
function saveUpdates(updates) {
return function(entity) {
// call .toObject() to get the data values
var entityObject = entity.toObject();
// now merge updates values with the data values
var updated = _.merge(entityObject, updates);
// use findByIdAndUpdate to update
// I added runValidators in case you have any validation you need
return Model
.findByIdAndUpdate(entity._id, updated, {
runValidators: true
})
.exec()
.then(updatedEntity => {
console.log(updatedEntity);
Model.find({_id: entity._id})
.then(data => console.log(data));
});
}
}

Resources