Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load document with a custom _id by Mongoose?

Here is my schema definition:

var DocSchema = new mongoose.Schema({
  _id: {
    name: String,
    path: String
  },
  label: String,
  ...
});
mongoose.model('Doc', DocSchema, 'doc_parse_utf8');
var Doc = mongoose.model('Doc');

And the documents have been inserted to mongodb by other program. Then I tried to query the document:

Doc.findOne({_id:{name:name,path:path}}, function(err, doc){
  if (err && err_handler) {
    err_handler(err);
  } else if(callback) {
    callback(doc);
  }
});

But, a cast error will be reported:

{ message: 'Cast to ObjectId failed for value "[object Object]" at path "_id"',
  name: 'CastError',
  type: 'ObjectId',
  value: { name: 'mobile', path: 'etc/' },
  path: '_id' }

I have searched this problem on mongoose's document, google and statckoverflow.com, however, there's no any solution for me. Please help, thanks.

like image 489
zjumper Avatar asked Feb 15 '23 05:02

zjumper


2 Answers

All you need to do is override the _id type by setting it to Mixed.

var UserSchema = new Schema({
    _id: Schema.Types.Mixed,
    name: String
});

This causes Mongoose to essentially ignore the details of the object.

Now, when you use find, it will work (nearly as expected).

I'd warn you that you'll need to be certain that the order of properties on the _id object you're using must be provided in the exact same order or the _ids will not be considered to be identical.

When I tried this for example:

var User = mongoose.model('User', UserSchema);

var testId = { name: 'wiredprairie', group: 'abc'};
var u = new User({_id: testId , name: 'aaron'});

u.save(function(err, results) {
    User.find().where("_id", testId)
        .exec(function(err, users) {
            console.log(users.length); 
    });
});

The console output was 0.

I noticed that the actual data in MongoDB was stored differently than I thought it had been saved:

{ 
  "_id" : { 
       "group" : "abc", 
       "name" : "wiredprairie" 
  }, 
  "name" : "aaron",
  "__v" : 0 
}

As you can see, it's not name then group as I'd coded. (It was alphabetical, which made sense in retrospect).

So, instead, I did this:

var User = mongoose.model('User', UserSchema);

var testId = { name: 'wiredprairie', group: 'abc'};
var u = new User({_id: testId , name: 'aaron'});

u.save(function(err, results) {
    User.find().where("_id", { group: 'abc', name: 'wiredprairie'})
        .exec(function(err, users) {
            console.log(users.length);
    });
});

Then, the console output was 1.

like image 189
WiredPrairie Avatar answered Feb 17 '23 20:02

WiredPrairie


I think you should re-design your schema. If the database is already on service, and can not change it now, you can temporary use this to solve the problem:

mongoose.connection.on('open', function () {
  mongoose.connection.db.collection('doc_parse_utf8').find({
      _id: {
        name: 'mobile',
        path: 'etc/'
      }
  }).toArray(function(err, docs) {
      console.log(err || docs)
  })  
})

As I know if you choose different order of fields in object find method will not work because

  _id: {
    name: 'mobile',
    path: 'etc/'
  }

and

  _id: {
    path: 'etc/',
    name: 'mobile'
  }

are different keys.

like image 43
damphat Avatar answered Feb 17 '23 21:02

damphat