nodejs mongodb object id to string - node.js

IN nodejs, with mongodb, mongoosejs as orm
I am doing this
I have a model, User
User.findOne({username:'someusername'}).exec(function(err,user){
console.log(user) //this gives full object with something like {_id:234234dfdfg,username:'someusername'}
//but
console.log(user._id) //give undefined.
})
Why? And how to get the _id to string then?

Try this:
user._id.toString()
A MongoDB ObjectId is a 12-byte UUID can be used as a HEX string representation with 24 chars in length. You need to convert it to string to show it in console using console.log.
So, you have to do this:
console.log(user._id.toString());

Take the underscore out and try again:
console.log(user.id)
Also, the value returned from id is already a string, as you can see here.

I'm using mongojs, and I have this example:
db.users.findOne({'_id': db.ObjectId(user_id) }, function(err, user) {
if(err == null && user != null){
user._id.toHexString(); // I convert the objectId Using toHexString function.
}
})

try this:
objectId.str;
see doc.

If you're using Mongoose, the only way to be sure to have the id as an hex String seems to be:
object._id ? object._id.toHexString():object.toHexString();
This is because object._id exists only if the object is populated, if not the object is an ObjectId

When using mongoose .
A representation of the _id is usually in the form (received client side)
{ _id: { _bsontype: 'ObjectID', id: <Buffer 5a f1 8f 4b c7 17 0e 76 9a c0 97 aa> },
As you can see there's a buffer in there. The easiest way to convert it is just doing <obj>.toString() or String(<obj>._id)
So for example
var mongoose = require('mongoose')
mongoose.connect("http://localhost/test")
var personSchema = new mongoose.Schema({ name: String })
var Person = mongoose.model("Person", personSchema)
var guy = new Person({ name: "someguy" })
Person.find().then((people) =>{
people.forEach(person => {
console.log(typeof person._id) //outputs object
typeof person._id == 'string'
? null
: sale._id = String(sale._id) // all _id s will be converted to strings
})
}).catch(err=>{ console.log("errored") })

function encodeToken(token){
//token must be a string .
token = typeof token == 'string' ? token : String(token)
}
User.findOne({name: 'elrrrrrrr'}, function(err, it) {
encodeToken(it._id)
})
In mongoose , the objectId is an object (console.log(typeof it._id)).

starting from Mongoose 5.4, you can convert ObjectId to String using SchemaType Getters.
see What's New in Mongoose 5.4: Global SchemaType Configuration.

Access the property within the object id like that user._id.$oid.

Really simple use String(user._id.$oid)

The result returned by find is an array.
Try this instead:
console.log(user[0]["_id"]);

try this : console.log(user._doc._id)

Related

$in function of mongo db is not working in nodejs as except :(

i want to get all the document from mongo db by the number list provided by the user but
the problem i m facing here is this ...
when i pass the value hardcoded the $in function works fine
but when i pass the req.body.userlist then it give me an empty array although the values are same
routes.post(/contect,function(req,res){
var userList = req.body.userList;
var contectList = ["3423432","23432423","32342"];
console.log(userList); //output ["3423432","23432423","32342"]
User.find({
"phoneNumber" : {
"$in":contectList
}
}.then(function(data){
console.log(data);
})
any one help whats wrong here
problem solved Thanks to Anthony Winzlet
the solution was simple all i need to parse the input as Anthony winzlet said
`You are passing string through postman. Try to parse it User.find({
"phoneNumber"
: { "$in": JSON.parse(userList) }}) – Anthony Winzlet`
it should be an array, so try using the spread operator.
$in
{ phonenumber: { $in: [...conectList] } }

MongoDB does not search for documents

but I cant find any items after ID,
Calendar.model inside is doc:
/* 1 */
{
"_id" : ObjectId("5a3425b58399c6c26cf1c848"),
"doctorID" : ObjectId("5a31392cc99fe923c0810096"),
"doctor" : "Bartłomiej Flis",
"calendar" : []
}
And in nodeJS API I am trying to find the doc using function:
router.get('/list-of-dates', (req, res)=> {
Calendar.find({ doctorID : req.query.doctorID})
.then((Calendar)=>{
console.log(Calendar)
res.send(Calendar)
})
.catch((err)=>{
console.log(err)
})
});
the value of req.query.doctorID is string -> 5a31392cc99fe923c0810096
Anyone can tell me why this function can't find any item? I think it is the fault that in the database variable doctorID is as ObjectId and in the API req.query.doctorID is a string, how to improve it in the API to work.
First, import in the beginning of the file the following:
const ObjectID = require('mongodb').ObjectId;
Then, change your search query to (i.e. wrap it into the ObjectId() function)
{ doctorID: ObjectId( req.query.doctorID ) }
What is the difference? MongoDB stores keys in ObjectId type, whereas you are trying to find something with type String. You were correct. That's why you do not get anything.
Let me know if that helps.

Mongoose accepts null for Number field

I have a mongoose schema where I'm storing a port number. I also have a default value set for the field.
port:{
type:Number,
default:1234
}
If I don't get any value via my API, it gets set to 1234.
However, If someone sends null, it accepts null and saves to database.
Shouldn't it covert null to 1234? null is not a number! Am I understanding it wrong?
I am considering the solution given here, but I dont want to add extra code for something that should work without it (unless I'm wrong and its not supposed to convert null to 1234)
See the comments in this issue:
https://github.com/Automattic/mongoose/issues/2438
null is a valid value for a Date property, unless you specify required. Defaults only get set if the value is undefined, not if its falsy.
(it's about dates but it can be applied to numbers just as well.)
Your options are to either:
add required to the field
add a custom validator that would reject it
use hooks/middleware to fix the issue
You might get away with a pre-save or post-validate (or some other) hook like this:
YourCollection.pre('save', function (next) {
if (this.port === null) {
this.port = undefined;
}
next();
});
but probably you'll have to use something like:
YourCollection.pre('save', function (next) {
if (this.port === null) {
this.port = 1234; // get it from the schema object instead of hardcoding
}
next();
});
See also this answer for some tricks on how to make null trigger default values in function invocation:
Passing in NULL as a parameter in ES6 does not use the default parameter when one is provided
This is unfortunate that Mongoose cannot be configured to tread null as undefined (with some "not-null" parameter or something like that) because it is sometimes the case that you work with data that you got in a request as JSON and it can sometimes convert undefined to null:
> JSON.parse(JSON.stringify([ undefined ]));
[ null ]
or even add null values where there was no (explicit) undefined:
> JSON.parse(JSON.stringify([ 1,,2 ]));
[ 1, null, 2 ]
As explained in mongoose official docs here
Number
To declare a path as a number, you may use either the Number global constructor or the string 'Number'.
const schema1 = new Schema({ age: Number }); // age will be cast to a Number
const schema2 = new Schema({ age: 'Number' }); // Equivalent
const Car = mongoose.model('Car', schema2);
There are several types of values that will be successfully cast to a Number.
new Car({ age: '15' }).age; // 15 as a Number
new Car({ age: true }).age; // 1 as a Number
new Car({ age: false }).age; // 0 as a Number
new Car({ age: { valueOf: () => 83 } }).age; // 83 as a Number
If you pass an object with a valueOf() function that returns a Number, Mongoose will call it and assign the returned value to the path.
The values null and undefined are not cast.
NaN, strings that cast to NaN, arrays, and objects that don't have a valueOf() function will all result in a CastError.

Why are mongoose references turning into IDs?

According to http://mongoosejs.com/docs/populate.html, if I set a ref property to an object, and not an ID, when getting it, I should get back an object and not an ID. I'm referring to this part of the page:
var guille = new Person({ name: 'Guillermo' });
guille.save(function (err) {
if (err) return handleError(err);
story._creator = guille;
console.log(story._creator.name);
// prints "Guillermo" in mongoose >= 3.6
// see https://github.com/LearnBoost/mongoose/wiki/3.6-release-notes
Here's my sample code:
var T1schema = new mongoose.Schema({
otherModel:{type:mongoose.Schema.Types.ObjectId, ref:"T2"}
});
var T1 = mongoose.model('T1', T1schema);
var T2schema = new mongoose.Schema({
email: {type: String},
});
var T2 = mongoose.model('T2', T2schema);
var t1 = new T1();
var t2 = new T2({email:"foo#bar.com"});
t1.otherModel = t2;
Now when I refer to t1.otherModel, it's just an ObjectId, and not a T2. For example:
console.log(t1.otherModel.email);
prints undefined instead of "foo#bar.com". Any ideas why? Note I'm using Mongoose 3.6.18 according to it's package.json.
Thanks!
I think your expectations here just don't match what mongoose does. The schema is a way of saying "model M's property P will always be of type T". So when you set a value, mongoose uses the schema definitions to cast the set value to the type the schema requires. Here's a little REPL session. Note setting a number property with a string value casts it to a number, but trying to store a boolean in a number field just ignores the errant value.
> var mongoose = require('mongoose')
> var schema = new mongoose.Schema({prop1: Number})
> var Model = mongoose.model('Model', schema)
> var m = new Model
> m.prop1 = 42
42
> m.prop1
42
> m.prop1 = "42"
'42'
> m.prop1
42
> m.prop1 = false
false
> m.prop1
42
So when your schema says something is going to be an ObjectId, if you give it a model instance, mongoose immediately converts it to an ObjectId in preparation for a write to the database, which is the common case. Normally if you just set that model instance, you don't need to get it back out of the parent model before saving the parent model to the database.
So the model instance getter defined properties are always going to return something compatible with the schema, and populate has to do with loading refs from the DB, but for whatever reason mongoose just doesn't work the same comparing a .populated instance with a non-populated instance. I can see why this is confusing and perhaps unexpected/disappointing though.
Mongoose is normalizing the instance to match the Schema, which specifies that otherModel is an ObjectId.
otherModel:{type:mongoose.Schema.Types.ObjectId, ref:"T2"}
So, Mongoose treats t1.otherModel = t2; the same as:
t1.otherModel = t2._id;
The ref isn't used until .populate() is called (either directly on the document or in a query), which needs both objects to be saved:
t2.save(function (err) {
t1.save(function (err) {
console.log(t1.otherModel);
// 7890ABCD...
t1.populate('otherModel', function () {
console.log(t1.otherModel);
// { email: 'foo#bar.com', _id: 7890ABCD..., __v: 0 }
});
});
});

MongoDB Node check if objectid is valid

How can I check whether an ObjectID is valid using Node's driver
I tried :
var BSON = mongo.BSONPure;
console.log("Validity: " + BSON.ObjectID.isValid('ddsd'))
But I keep getting an exception instead of a true or false. (The exception is just a 'throw e; // process.nextTick error, or 'error' event on first tick'
This is a simple check - is not 100% foolproof
You can use this Regular Expression if you want to check for a string of 24 hex characters.
var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$")
checkForHexRegExp.test("i am a bad boy")
// false
checkForHexRegExp.test("5e63c3a5e4232e4cd0274ac2")
// true
Regex taken from github.com/mongodb/js-bson/.../objectid.ts
For a better check use:
var ObjectID = require("mongodb").ObjectID
ObjectID.isValid("i am a bad boy")
// false
ObjectID.isValid("5e63c3a5e4232e4cd0274ac2")
// true
isValid code github.com/mongodb/js-bson/.../objectid.ts
isValid() is in the js-bson (objectid.ts) library, which is a dependency of node-mongodb-native.
For whoever finds this question, I don't recommend recreating this method as recommend in other answers. Instead, continue using node-mongodb-native like the original poster was using, the following example will access the isValid() method in js-bson.
var mongodb = require("mongodb");
var objectid = mongodb.BSONPure.ObjectID;
console.log(objectid.isValid('53fbf4615c3b9f41c381b6a3'));
July 2018 update: The current way to do this is:
var mongodb = require("mongodb")
console.log(mongodb.ObjectID.isValid(id))
As an extension of Eat at Joes answer... This is valid in node-mongodb-native 2.0
var objectID = require('mongodb').ObjectID
objectID.isValid('54edb381a13ec9142b9bb3537') - false
objectID.isValid('54edb381a13ec9142b9bb353') - true
objectID.isValid('54edb381a13ec9142b9bb35') - false
If you are using mongoose then you can use mongoose for validation rather than depending on any other library.
if (!mongoose.Types.ObjectId.isValid(req.id)) {
return res.status(400).send("Invalid object id");
}
#GianPaJ's snippet is great but it needs to be extended slightly to cover non hex objectID's. Line 32 of the same file indicates objectID's can also be 12 characters in length. These keys are converted to a 24 character hex ObjectID by the mongodb driver.
function isValidObjectID(str) {
// coerce to string so the function can be generically used to test both strings and native objectIds created by the driver
str = str + '';
var len = str.length, valid = false;
if (len == 12 || len == 24) {
valid = /^[0-9a-fA-F]+$/.test(str);
}
return valid;
}
Below is my model where I am trying to validate subject id that is of type objectId data using JOI (Joi.objectId().required()):
const Joi = require('joi');
const mongoose = require('mongoose');
const Category = mongoose.model('Category', new mongoose.Schema({
name: String
}));
function validateCategory(category) {
const schema = {
name: Joi.string().min(5).max(50).required(),
subject_id: Joi.objectId().required(),
};
return Joi.validate(category, schema);
}
exports.Category = Category;
exports.validate = validateCategory;
joi-objectid validates that the value is an alphanumeric string of 24 characters in length.
MongoDB ObjectId validator for Joi.
Follow this regular expression :
in js
new RegExp("^[0-9a-fA-F]{23}$").test("5e79d319ab5bfb2a9ea4239")
in java
Pattern.compile("^[0-9a-fA-F]{23}$").matcher(sanitizeText(value)).matches()
You can use Cerberus and create a custom function to validate and ObjectId
from cerberus import Validator
import re
class CustomValidator(Validator):
def _validate_type_objectid(self, field, value):
"""
Validation for `objectid` schema attribute.
:param field: field name.
:param value: field value.
"""
if not re.match('[a-f0-9]{24}', str(value)):
self._error(field, ERROR_BAD_TYPE % 'ObjectId')
## Initiate the class and validate the information
v = CustomValidator()
schema = {
'value': {'type': 'objectid'}
}
document = {
'value': ObjectId('5565d8adba02d54a4a78be95')
}
if not v(document, schema):
print 'Error'

Resources