I need to pass to the updateMany method in a Node/Typescript software a piece of query retrieved from the database:
{'$unset': {'extras' : {'origin': ''}}}
In the db, the above query is stored as a field of an Object:
"cleanup.aggregated_records_to_modify" : {
"update_fields_by" : "{'$unset': {'extras' : {'origin': ''}}}"
}
If I pass the update_fields_by to the updateMany mondodb Nodejs driver method, I have an error saying ""MongoError: the update operation document must contain atomic operators." (it receives a string instead of an object?!?); if, instead, I create an object variable:
const queryTemp = { $unset: { extras: { origin: "" } } };
to give to the updateMany, all goes well.
How can I retrieve the field from db and correctly pass it to the update method as an object?
If you use JSON.parse(foo) on your variable, to convert it from string to an object
There was a problem (a bug?) with the tool I use to manage MondoDB; I cannot store an object with a key starting with $ because I receive the error "Illegal argument: Invalid BSON field name $unset". I have add the $ symbol programmatically.
Related
When I try to use Firebase.Firestore.set() with an object, I get an error saying "(FirebaseError): Function DocumentReference.set() called with invalid data. Unsupported field value: a custom ql object"
I'm using Firebase in a React class, and I tried creating the object right in the function and defining it separately as shown below:
if (authUser) {
const userObj = {
name: authUser.displayName,
uid: authUser.uid,
email: authUser.email,
emailVerified: authUser.emailVerified,
providerData: authUser.providerData
}
this.db.collection("users").doc(authUser.uid).set(userObj, { merge: true })
}
Most likely the providerData (which comes from the identity provider) contains data of a type that Firestore can't handle. To fix this problem, either don't store the provider data, or convert it into a compatible type with this hack:
providerData: JSON.parse(JSON.stringify(authUser.providerData))
Your problem is that you are trying to copy an instance of an object, (i guess is a graphql object) and firebase does not support that, you need to use primitive values. Make sure you copy strings on all the properties instead of pointers to the class.
Let's use a basic mongodb query that returns one item:
const result = await db.myCollection.findById('xxxx')
return result;
This query result given to graphql works fine.
But now, if I return a result.toObject(), it's not working anymore.
I got this following error:
"message": "Cannot return null for non-nullable field MyCollection.id."
Why with toObject(), the mapping between _id and id can't be done?
The id generated by MongoDB will be a _id field -- it's mongoose that's actually mapping it for you.
Mongoose assigns each of your schemas an id virtual getter by default
which returns the documents _id field cast to a string, or in the case
of ObjectIds, its hexString. If you don't want an id getter added to
your schema, you may disable it passing this option at schema
construction time.
They key here is that the id field is a virtual getter. In order to include those in the generated object, you have to pass the appropriate option to toObject:
result.toObject({ virtuals: true })
See the docs or this answer for more details.
I was trying to console.log(record._id) all of records on my mongodb collection using Mongoose. I kept getting undefined for each of the _id values.
I struggled until I bumped into this post. Then I used console.dir to find the location of the _id and used that in my console.log:
MySchemaModel.find({}).then(function(records) {
records.forEach(function(record) {
console.log(record._doc._id); // <-- I added ._doc
});
});
But, this looks down-right hacky. Is there a better way to do this?
NOTE: This isn't just something that affects console.log. I'm just keeping the question narrow.
If you want to customize/edit record then you should use .lean() function.The .lean() function will turn it into a normal JavaScript object. If you don't use .lean() function then each record is still a mongoose document and _id behaves differently in that context. So can use like
MySchemaModel.find({}).lean().exec(function(error, records) {
records.forEach(function(record) {
console.log(record._id);
});
});
N.B: when use .exec() then first parameter used for error and second one for success data.
Mongoose assigns each of your schemas an id virtual getter by default
which returns the documents _id field cast to a string, or in the case
of ObjectIds, its hexString. If you don't want an id getter added to
your schema, you may disable it passing this option at schema
construction time.
Source: Mongoose Docs
var schema = new Schema({ name: String }, { id: false });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p.id); // '50341373e894ad16347efe01'
I guess the issue is with .then promise, I have never seen that.
MySchemaModel.find({}).then
So just try simple .exec call with callback.
MySchemaModel.find({}).exec(function(records) {
records.forEach(function(record) {
console.log(record._id);
});
});
The problem is that each record is still a mongoose document and _id behaves differently in that context. The .lean() function will turn it into a normal JavaScript object.
MySchemaModel.find({}).lean().then(function(records) {
records.forEach(function(record) {
console.log(record._id);
});
});
you can also use the .map() method :
MySchemaModel.find({}).exec(function(records) {
console.log(records.map(record => record._id);
});
if you are using a model you don't get the full object but an instance of _doc as record
so you should directly
console.log(record._id)
or
console.log(record._id.valueOf())
but when you return record as response you get the full object so it's better to use .find().lean()
So I'm aware how I should add any regular string/object to a JSON object - however, I need to add the following Mongo command to my JSON object:
$set : { "author" : req.body.name }
As you can see, it's not as simple as just doing:
myJsonObject.author = "$set..." etc.
Sorry if this is a dupe question - this isn't the easiest subject to Google without tons of unrelated answers popping up.
The reason I need to know this because I want to be able to build a JSON object based on what the user has changed in the form. So a new problem I have encountered is that even if I can build the JSON object with multiple items to change, MongoDB only updates the last item in the object. My example JSON object is here:
updateItem = {
$set : { "name" : "Squid bonobo" },
$set : { "author" : "Mardy Bum" }
};
and the snippet of code which issues the update command is as follows:
updateData.update(searchItem, updateItem, false, true, function(err, results) {
console.log(results);
db.close();
});
I found this solution at the following git site.
Can anybody help with either of these questions?
Thanks for your help :)
Cameron
You need to form your JSON in the below structure:
updateItem = {
$set : { "name":"Squid bonobo","author":"Mardy Bum"}
}
Javascript Objects can be declared with duplicate keys/properties, but their values get over-written, with the latest bound value for the key, in any order.
Here, $set is a key/property which has been set twice to the same object referenced by the variable updateItem, hence only one value, that is last encountered, will be associated to the key. In this case, the value that takes precedence is:
$set:{ "author":"Mardy Bum" }
and the final query that gets executed becomes,
updateItem = {
$set : { "author" : "Mardy Bum" }
};
I'm creating an application in Node that has some CRUD components. On one of my data objects, I have a save() method that is meant to update a record if the object has an id that is found in the collection, or upsert a new document if not. Additionally, if doing an upsert I'd like to get back the _id for the document generated by Mongo.
It seems that findAndModify would do this, and, indeed, it does return an _id value from the database. In my query clause, I am filtering by _id. If my data object doesn't have an id, Mongo correctly does an upsert, however, no matter what _id value it returns, in addition to the the keys I am setting in the update clause, it also sets the _id on the document based on what value I used in the query clause. Some code for clarity:
User.prototype.save = function(callback) {
var that = this;
var args = {
'query' : { _id: this.getId() }, //getId() returns empty string if not set
'update' : { $set : {
firstName : this.firstName,
lastName : this.lastName,
email : this.email
//_id : this.getId()
// which is blank, is magically getting added due to query clause
}},
'new' : true,
'upsert' : true,
'fields' : {'_id' : true}
};
this.db.collection(dbName).findAndModify(args, function(err, doc){
if(!that.getId()) {
that.setId(doc._id);
}
if (typeof(callback) === "function"){
callback.call(that);
}
});
}
I'm simply looking for the semantics of update that also happens to return a Mongo-generated _id on upsert. I do not want the values of the query clause to additionally be appended as if they were in the update map. Is there any way to achieve what I am getting at?
You can generate the _id client side, with new new require('mongodb').ObjectID()
Then you can just do a regular upsert (no need to do findandmodify) because you already have the _id.
However, if you are using findAndModify, keep in mind that the node driver accepts the arguments to this function positionally, not as an object (like in the regular mongo shell).
The correct format to do findandmodify with the node driver looks like this:
collection.findAndModify(criteria, sort, update[, options, callback])
(options and callback are optional params). Full docs here:
https://github.com/mongodb/node-mongodb-native/blob/master/docs/insert.md