How to clone a mongoose document? - node.js

This is a followup to Easiest way to copy/clone a mongoose document instance?, which isn't working for me.
The following code throws a "cannot edit Mongo _id" field, rather than wiping the ._id and creating a new document in the collection.
Is there a better way to clone all values of a document into a new document, for further use/testing/etc?
I'm on Mongoose 3.8.12/Express 4.0, and I have also tested this on creating a new ObjectID in the 'undefined' s1._id field below.
router.route('/:sessionId/test/:testId')
.post(function(req,res){
Session.findById(req.params.sessionId).exec(
function(err, session) {
var s1 = new Session();
s1 = session;
s1._id = undefined;
console.log('posting new test', s1._id); // your JSON
s1.save(function(err) {
if (err)
res.send(err);
res.json( 'new session ', req.body );
});
}
);
});

You need to create a new id for the document you want to clone and set isNew to true, so given "session" is the document you want to clone:
session._doc._id = mongoose.Types.ObjectId();
session.isNew = true;
session.save(...);

The answer is:
var s1 = new Session(session);
s1._id = undefined;

Related

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

Mongoose findById returns null even with valid id

I have already seen the discussion about the following question with a similar title
mongoose 'findById' returns null with valid id
But my problem is not the database name since all my other connections with the same database in fact the queries on the same collection are working fine.
I am using mongoose 4.13.6, node js 6.11 and mongo 3.4.
It is a post request .
var query=req.body;
I am sending the search parameters as
var findFruit =
{
_id:query._id
}
When I print my findFruit I get :
_id:'5a1cf77920701c1f0aafb85e'
The controller function for this is :
Fruit.findById(findFruit._id,function(err,fruit){
if( _.isNull(err) ){
var response = genRes.generateResponse(true,"found successfully");
callback(response);
}
else{
var response = genRes.generateResponse(false,"there occured some error : "+err);
callback(response);
}
})
I even tried find
Fruit.find(findFruit,function(err,fruit){
if( _.isNull(err) ){
var response = genRes.generateResponse(true,"found successfully");
callback(response);
}
else{
var response = genRes.generateResponse(false,"there occured some error : "+err);
callback(response);
}
})
The collection for sure has the entry under this id .
I went through this git issue as well https://github.com/Automattic/mongoose/issues/3079
Unfortunately I cannot downgrade mongoose as it might affect multiple other working functions.
Edit :
I tried creating ObjectId like :
var mongoose = require('mongoose');
var ObjectID = require('mongodb').ObjectID;
var objectId = new ObjectID();
// Convert the object id to a hex string
var originalHex = objectId.toHexString();
// Create a new ObjectID using the createFromHexString function
var newObjectId = new ObjectID.createFromHexString(query._id);
The model file :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var FruitSchema = new Schema({
name : {type : String, unique : true},
color : {type : String}
});
module.exports = mongoose.model('Fruit', FruitSchema);
All my findById("id") calls returned null.
When looking at the collection with Compass I realized that all my _id elements were Strings. Note that the entire collection was imported.
I created a new element in Compass and the _id was created as ObjectId! and when I called findById("id") with that element's id it worked!
My conclusion is that there is obviously a bug with import. I have not found a way to convert the string _id fields to ObjectId's in the actual collection.
All my findById("id") calls returned null, when _id elements are Strings.
In the first place:
Check your mongodb database, if _id is stored as String, findById(id) can not find since it identifies ObjectId. If you've used import database by using mongoimport command and including _id in JSON:
Solution 1:
modify your JSON and for each document, change _id for instance:
_id: "5a68fde3f09ad7646ddec17e" to the following and run mongoimport again:
"_id": { "$oid": "5a68fde3f09ad7646ddec17e" }
Solution 2:
delete _id in the JSON file, drop collection and import again. Mongo will auto-create _id.
After any of solutions above, findById("id") will work.
Secondly:
Specifically in such cases where your _id elements are string, might be a better idea to use mongodb package: npm i mongodb
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db("your_db_name");
dbo.collection("fruits_collection")
.find({_id:'5a1cf77920701c1f0aafb85e'})
//.find({_id:'5a1cf77920701c1f0aafb85e'}, { projection: { _id: 0, name: 1, color: 1} }) // to select specific columns desired
.toArray(function (err, result) {
if (err) throw err;
console.log(result);
db.close();
});
});
The above simple code, assumed you manage error handling yourself, either through try-catch, or
sending 404 as status code, or redirect to error page template, depending on whether the code is embedded in the Express route handler or not.
Hope this helped .. :)
Still trying to figure out why findById didn't work for me but the following piece of code did it
var mongoose = require('mongoose');
var newObjectId=new mongoose.Types.ObjectId(query._id);
var params={
'_id':newObjectId
}
Fruit.find(params).exec(function (err,fruit) {
if( _.isNull(err) ){
var response = genRes.generateResponse(true,"found successfully");
callback(response);
}
else{
var response = genRes.generateResponse(false,"there occured some error : "+err);
callback(response);
}
})
#Shoom. Yes, worked for me, thanks. findById() expects ObjectID, not a String.
I did not have a constraint to create documents with a specific id, so I imported with no _id. The db had newly-assigned _id as ObjectID.
findById(id), (and updateOne({ _id: id }, ...), started working as expected.

Node/Mongoose: Synchronous Find/Save/Delete between Collections: collection1.find(collection2.save(collection1.remove()))

I have a database of users and I want to implement deleting a user from one collection (Users). But before that user is deleted, I wanted to save it to another collection for backup/tracking (DeletedUsers).
So the sequence should be:
1) Find user, 2) save user to DeletedUsers, 3) delete user from Users.
Because this needs to be synchronous, I've nested the functions and sequenced through callbacks. The problem is the save to DeletedUsers is not working.
Standalone, the save to DeletedUsers works, just not when it's nested in the User.find().
I have setup two different Schemas for the Users/Deleted Users:
var User = mongoose.model('User', new Schema({data}));
var DeletedUser = mongoose.model('DeletedUser', new Schema({data}));
Implementation of the delete:
exports.postDeleteUser = function(req,res) {
var conditions = { '_id': req.params.user_id };
// Create the new deletedUser object to add to
// the DeletedUsers collection
var deletedUser = new DeletedUser();
User.findOne(conditions, function(err, user) {
if (!user) {console.error(err);
} else {
// Copy over data to the new deletedUser object
for (prop in user) {deletedUser[prop] = user[prop];}
// This is where I save the deletedUser to the
// new collection.
// ** This is not executing ** //
deletedUser.save(function(err) {
if (err) {
console.error(err);
renderViewUser(user['_id'], 0, req, res);
} else {
// However, this delete from Users *is* working
User.find(conditions).remove(function() {
res.redirect('/');
});
};
});
};
});
};
Thanks for your help.
As #RaR pointed out, there are some hidden properties that are keeping the new data object from saving to the new collection, not just _id.
Copying all properties does not work:
for (prop in user) {deletedUser[prop] = user[prop];}
Only specific properties must deliberately copied:
var properties = ['prop1', 'prop2'....];
properties.forEach(function(i) {
deletedUser[i] = user[i];
});

Update MongoDB collection - JavaScript

I am trying to update a value in a collection. The user clicks a button, and a number corresponding to that button, gets sent to the server to be added to the collection.
I cannot get the collection to update, but it works fine in the console if i use db.orders.update()
orders model:
// DB Initiation stuff
var orderSchema = new mongoose.Schema({
status: String,
rated: Number
});
var collection = 'orders';
var Order = db.model('Order', orderSchema, collection);
module.exports = Order;
client side (when button click)
// starID = 5; id = 50e6a57808a1d92dcd000001
socket.emit('rated', {rated: starID, id: id});
socket.js:
var Order = require('../models/orders');
socket.on('rated', function(data) {
/* Probably a better way to do this but, wrap
* the id in 'ObjectId(id)'
*/
var id = 'ObjectId("'+data.id+'")';
Order.update( {_id: id}, {$set: {rated: data.rated}} );
socket.emit('updated', {
note: 'Some HTML notification to append'
});
});
Let Mongoose do the casting of the id string to an ObjectId:
socket.on('rated', function(data) {
Order.update( {_id: data.id}, {$set: {rated: data.rated}} );
socket.emit('updated', {
note: 'Some HTML notification to append'
});
});
Mongoose expects a String as id. So passing an ObjectId does not work.
Try:
Order.update( {_id: id.toString()}, ....... );
It is safe to use toString with both String and ObjectId.
I tried everything stated and it just didn't seem to work, so I changed the update code to:
Order.findOne({_id : id}, function(err, doc) {
doc.rated = data.rated;
doc.status = data.status;
doc.save();
});
And now it works fine. Thank you to everyone who contributed to answering

NodeJS + MongoDB: Getting data from collection with findOne ()

I have a collection "companies" with several objects. Every object has "_id" parameter. I'm trying to get this parameter from db:
app.get('/companies/:id',function(req,res){
db.collection("companies",function(err,collection){
console.log(req.params.id);
collection.findOne({_id: req.params.id},function(err, doc) {
if (doc){
console.log(doc._id);
} else {
console.log('no data for this company');
}
});
});
});
So, I request companies/4fcfd7f246e1464d05000001 (4fcfd7f246e1464d05000001 is _id-parma of a object I need) and findOne returns nothing, that' why console.log('no data for this company'); executes.
I'm absolutely sure that I have an object with _id="4fcfd7f246e1464d05000001". What I'm doing wrong? Thanks!
However, I've just noticed that id is not a typical string field. That's what mViewer shows:
"_id": {
"$oid": "4fcfd7f246e1464d05000001"
},
Seems to be strange a bit...
You need to construct the ObjectID and not pass it in as a string. Something like this should work:
var BSON = require('mongodb').BSONPure;
var obj_id = BSON.ObjectID.createFromHexString("4fcfd7f246e1464d05000001");
Then, try using that in your find/findOne.
Edit: As pointed out by Ohad in the comments (thanks Ohad!), you can also use:
new require('mongodb').ObjectID(req.params.id)
Instead of createFromHexString as outlined above.
That's because _id field in mongo isn't of string type (as your req.params.id). As suggested in other answers, you should explicitly convert it.
Try mongoskin, you could use it like node-mongodb-native driver, but with some sugar. For example:
// connect easier
var db = require('mongoskin').mongo.db('localhost:27017/testdb?auto_reconnect');
// collections
var companies = db.collection('companies');
// create object IDs
var oid = db.companies.id(req.params.id);
// some nice functions…
companies.findById();
//… and bindings
db.bind('companies', {
top10: function(callback) {
this.find({}, {limit: 10, sort: [['rating', -1]]).toArray(callback);
}
});
db.companies.top10(printTop10);
You can use findById() which will take care of the id conversion for you.
company = Company.findById(req.params.id, function(err, company) {
//////////
});
In case these didn't work for you, this worked for me for accessing a blog post:
const getSinglePost = async (req, res) => {
let id = req.params.id;
var ObjectId = require('mongodb').ObjectId;
const db = await client.db('CMS');
const data = await db.collection("posts").findOne({ _id: ObjectId(id) })
if (data) {
res.status(200).send(data)
} else res.status(400).send({ message: "no post found" })
}

Resources