Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I know in mongodb if a field is a Date type?

I'm working on a NodeJS+Mongodb app.

I've just inserted one record into mongodb using the console client:

db.user.save({myId:11111, myDate: ISODate("2012-04-30T00:00:00.000Z")})

The thing is, when I'm in node.js, I need to know if "myDate" field is really a Date type, in order to perform a data range query, etc.

I tried the following.

1. on the mongo client console:

typeof db.user.myDate --> It returns "Object"
db.user.myDate instanceof Date --> It returns "false"

2. on my Nodejs code,

I'm trying to get the type calling this getTypeMembers function. (obj comming from a db query)

exports.getTypeMembers = function(obj) {
obj = JSON.parse(JSON.stringify(obj)

for(var _k in obj){
    if(Object.prototype.toString.call(obj[_k]) === '[object Array]' ) {
        obj[_k] = "Array";
    }
    else if(typeof(obj[_k])=="object"){
        obj[_k] = this.getTypeMembers(obj[_k]);
    }else{
        obj[_k] = typeof (obj[_k]);
    }
}
return obj;

};

What I get in this method is: "String", when I need "Date"

Is there any other way to get some kind of "Date" result?

like image 909
larrytron Avatar asked Sep 27 '12 11:09

larrytron


4 Answers

I finally found my solution.

As @christkv said, once you call a JSON stringify, all original types are definitely lost. So, thinking in this way, my method getTypeMembers works perfectly for me.

Notice that, obj parameter is coming from the DB, and also "_id" (mongodb identificator) is directly ommited in order to avoid problems when performs the recursive function:

exports.getTypeMembers = function(obj) {
    for(var _k in obj){
        if (_k =="_id") continue;
        if (Object.prototype.toString.call(obj[_k]) === "[object Number]"){
            obj[_k] = "Number";
        }else if (Object.prototype.toString.call(obj[_k]) === "[object String]"){
            obj[_k] = "String";
        }else if (Object.prototype.toString.call(obj[_k]) === "[object Date]"){
            obj[_k] = "Date";
        } else if(Object.prototype.toString.call(obj[_k]) === '[object Array]' ) {
            obj[_k] = "Array";
        } else if(typeof(obj[_k])=="object"){
            obj[_k] = this.getTypeMembers(obj[_k]);
        } else{
            obj[_k]  = (typeof obj[_k])[0].toUpperCase() + (typeof obj[_k]).slice(1);
        }
    }
    return obj;
};

In the Mongo console part, I only can get the type doing the following:

db.user.find({},{myDate:1}).forEach(function(f) { print (f.myDate instanceof Date) } );

But If I do,

typeof db.user.myDate --> It returns "Object"
db.user.myDate instanceof Date --> It returns "false"

I still don't undertand why.

like image 74
larrytron Avatar answered Nov 04 '22 14:11

larrytron


You can use the $type operator to query for fields of a specific type:

db.col.query({a: {$type: 9}})

9 being the number for the date type, see http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24type

As to determining the type inside node.js, it depends on your driver. I've used none, but it might be a specific prototype, like how ObjectId is. Maybe you could examine the object and look for the constructor name.

like image 21
sapht Avatar answered Nov 04 '22 15:11

sapht


I'm a little confused by the use of

db.user.myDate

in your example. Are you making this exact call on the Db object that node-mongodb-native is giving you? If so, you should be getting undefined because you are not actually querying the database, but instead checking a property of the Db javascript object (a property that is in almost all certainty not there).

Could you post the code that you are running from the node.js process? I tested out your code, using an identical shell insertion, and once I retrieved the doc from the database in node.js,

doc.myDate instanceof Date

returned true.

I also am not familiar with your application, but it seems ill-advised to me to be querying collections where you do not know the types of the data. Why are you unsure what type of value the other applications are using for the myDate field?

Edit:

var coll = new mongo.Collection(client, 'user');
    coll.find({}).toArray(function(err, docs) {
    docs.forEach(function (doc) {
        console.log(doc);
        console.log(doc.myDate instanceof Date);
    });
});

logs "true" for me when run in nodejs after an identical shell insert to yours. What happens if you run it?

like image 27
shelman Avatar answered Nov 04 '22 14:11

shelman


Judging by your latest edit I believe I see the problem. You are parsing the document into JSON. Unlike BSON, JSON does not support the literal creation and storage of BSON objects. The ISODate object is a BSON data type.

So when you convert to JSON you actually lose this object.

You can solve this two ways:

  • Don't convert to JSON until you have checked the field type
  • Every object has properties. Date is no different, it should have a $date property (I believe) which you can check if isset to see if the field is of type date
like image 28
Sammaye Avatar answered Nov 04 '22 15:11

Sammaye