Deleting _id from object coming from mongodb doesn't work - node.js

I am using graphql to get some data from mongodb database. So, I was making an api which on running saves data in main collection but also saves data in some other collection with a couple of more data. I was trying to delete _id from the data that I get on saving on main collection but it's not working and I can't figure out why.
Here's what's happening
const data = await User.getResolver('updateById').resolve({ //default resolver from graphql-compose library to update a record. Returns the whole document in record //
args: {...rp.args}
})
const version = '4'
const NewObject = _.cloneDeep(data.record);
NewObject.version = version;
NewObject.oldId = data._id;
_.unset(NewObject, '_id'); //this doesn't work neither does delete NewObject._id//
console.log('new obj is', NewObject, version, NewObject._id, _.unset(NewObject, '_id')); //prints _id and surprisingly the unset in console.log is returning true that means it is successfully deleting the property//
I am very confused to what I am doing wrong.
Edit: Sorry should have mentioned, but according to lodash docs _.unset returns true if it successfully deletes a property.

Turn's out mongoDb makes _id as a Non configurable property. So, to do this I had to make use of toObject() method to make an editable copy of my object.
const NewObject = _.cloneDeep(data.record).toObject();
With this I was able to delete _id.
Alternatively _.omit of lodash also works.

Related

Mongoose (6.x) populate after save

In Mongoose 6 execPopulate() seemed to be removed. Due to this, the below code returns error.
const t = new MyModel(value)
return t.save().then(t => t.populate('my-path').execPopulate())
I'd like to know how to populate after save in Mongoose 6 or later. FYI, the newly created and unpopulated instance should be used before populating so I don't wanna use MyModel.populate().
The solution is super easy. populate() itself returns the correct promise.
const t = new MyModel(value)
return t.save().then(t => t.populate('my-path'))
I was mistaken for not populating the relevant object, but I found it to work.

How to create a new Mongoose document, and then update before saving

I'm trying to create a new Mongoose document first
let newTrade = new TradeModel({
userId: userId,
symbol: symbol
})
Then I need to send this item to another server, to get the other details
let orderReceived = await sendOrderToServer(newTrade);
And then I want to merger this in with the new document and save
newTrade = {...newTrade, ...orderReceived}
But once I alter the original document, I loose access to the .save() method. I cant run .save() first becasue its missing required fields. I really just need the Trade._id first before sending to the other server which is why I'm doing it this way. Any suggestions? thanks.
You can use the mongoose.Types.ObjectId() constructor to create an id and then send that to your server, when the response comes back, create a document based on that.
EDIT: Adding few examples for clarity
let newTradeId = new mongoose.Types.ObjectId(); // With "new" or without, Javascript lets you use object constructors without instantiating
let orderReceived = await sendOrderToServer(newTradeId);
let newTrade = new TradeModel({ ...orderReceived }); // Create the newTrade by destructuring the order received.
// TADA! We are done!

Express, Mongoose, db.findOne always returns same document

I am attempting a CRUD app with MEAN stack. I am using mongoose in Express to call to the MongoDB. I am using the FindOne function with a specified parameter, and it's always returning the same (incorrect) document.
I know I am connected to the correct database, since I get a document back from that collection, but it's always the same document, no matter what I pass as the parameter.
module.exports = mongoose.model('Player', playersSchema, 'players'); //in player.js
const Player = require('./model/players');
app.get('/api/player/:id', (req, res) =>{
Player.findOne({id: req.params.playerId},
function(err, player) {
if(err) {
res.json(err);
}
else {
res.json(player);
}
});
});
I have 3 separate "players", with three distinct "playerID" fields (38187361, 35167321, 95821442). I can use Postman to GET the following URL, for example:
http://localhost:3000/api/player/anythingyouWantInHere
and it will return 38187361, the first document. I've been over this website, many tutorials, and the Mongoose documentation and I can't see what I'm doing wrong..
I'd like to eventually find by playerId OR username OR email, but one hurdle at a time...
From the mongoose documentation of findOne, if you pass Id a null or an empty value, it will query db.players.findOne({}) internally which will return first document of the collection everytime you fetch. So make sure you are passing non-empty id here.
Note: conditions is optional, and if conditions is null or undefined,
mongoose will send an empty findOne command to MongoDB, which will
return an arbitrary document. If you're querying by _id, use
findById() instead.
Your route is '/api/player/:id', so the key on the req.params object will be 'id' not 'playerId'.
I don't know what/where/if you're populating the playerId param, but if you update your query to call req.params.id it should actually change the document based on the path as you seem to be wanting to do.
I had the same problem, and it was that the name of column's table was different from the model I had created.
In my model the name of the wrong column was "role" and in my table it was "rol".

node js mongoose trying to overwrite _id field before saving

I'm trying to override the _id field of a mongo doc to an integer with an auto inc.
I've tried some modules and none of them worked for me. I thought I'd write something of my own, like this :
productSchema.pre('save', function (next) {
this._id = 5; //or what ever
next();
});
but it didn't work and the _id field was null. Even tried this._doc['id'] = 5. I thought in merging the _id to the doc before it was saved by a redis but that's ugly since the redis.get is async so I'd have to pass the save action inside the redis callback.
Any solutions?

mongoose get db value in pre-save hook

I want to know what the 'clean' value of a dirty prop is in a pre-save mongoose hook like this:
UserSchema.pre('save', function(next) {
var user = this;
if (user.isModified('password')){
//i want to know what the value of user.password was before it was changed
}
next()
}
Is it possible to look up the old value without looking it up in the db?
By default, the old values are not stored. You would have to do is track the old data with a post init hook (a mongoose feature).
What we do is attach copy of the original document to all items pulled from MongoDB. We have this code for each schema we need to get pre-dirty data for comparison:
schema.post( 'init', function() {
this._original = this.toObject();
} );
NodeJS is pretty efficient, and does copy on write when possible, so you don't see double the memory consumption unless you modify the entire document. Only then does _original actually consume double the memory.
So in a pre-save hook, from what I can tell by reading this section of the source code, I don't think the previous value is stored anywhere. So you'll have to load the document from mongodb to get it.
However, you might want to use the virtuals mechanism instead of a pre-save hook to store the old value before changing it to the new value.
var virtual = schema.virtual('password');
virtual.set(function (v) {
var this._oldPassword = this.password;
return v;
});
Experiment with something along those lines and see if you can make something work suitably.

Resources