find by _id with Mongoose

2020-08-09 10:01发布

问题:

I am having trouble with a simple findById with mongoose.

Confirmed the item exists in the DB

db.getCollection('stories').find({_id:'572f16439c0d3ffe0bc084a4'})

With mongoose

  Story.findById(topic.storyId, function(err, res) {
    logger.info("res", res);
    assert.isNotNull(res);
  });

won't find it.

I also tried converting to a mongoId, still cannot be found (even though mongoose supposedly does this for you)

var mid = mongoose.Types.ObjectId(storyId);
let story = await Story.findOne({_id: mid}).exec();

I'm actually trying to use this with typescript, hence the await.

I also tried the Story.findById(id) method, still cannot be found.

Is there some gotcha to just finding items by a plain _id field? does the _id have to be in the Schema? (docs say no)

I can find by other values in the Schema, just _id can't be used...


update: I wrote a short test for this.

describe("StoryConvert", function() {


  it("should read a list of topics", async function test() {
    let topics = await Topic.find({});

    for (let i = 0; i < topics.length; i ++) {
      let topic = topics[i];
    // topics.forEach( async function(topic) {
      let storyId = topic.storyId;
      let mid = mongoose.Types.ObjectId(storyId);
      let story = await Story.findOne({_id: mid});
      // let story = await Story.findById(topic.storyId).exec();
      // assert.equal(topic.storyId, story._id);
      logger.info("storyId", storyId);
      logger.info("mid", mid);
      logger.info("story", story);
      Story.findOne({_id: storyId}, function(err, res) {
        if (err) {
          logger.error(err);
        } else {
          logger.info("no error");
        }
        logger.info("res1", res);
      });

      Story.findOne({_id: mid}, function(err, res) {
        logger.info("res2", res);
      });

      Story.findById(mid, function(err, res) {
        logger.info("res3", res);
        // assert.isNotNull(res);
      });

    }

  });


});

It will return stuff like

Testing storyId 572f16439c0d3ffe0bc084a4

Testing mid 572f16439c0d3ffe0bc084a4

Testing story null

Testing no error

Testing res1 null

Testing res2 null

Testing res3 null

I noticed that topic.storyId is a string not sure if that would cause any issues mapping to the other table. I tried also adding some type defs

  storyId: {
    type: mongoose.Schema.Types.ObjectId,
    required: false
  }

回答1:

Because this query finds the doc in the shell:

db.getCollection('stories').find({_id:'572f16439c0d3ffe0bc084a4'})

That means that the type of _id in the document is actually a string, not an ObjectId like Mongoose is expecting.

To find that doc using Mongoose, you'd have to define _id in the schema for Story as:

_id: { type: String }


回答2:

If your Mongo schema is configured to use Object Id, you query in nodeJS using

models.Foo.findById(id)

where Foo is your model and id is your id. here's a working example

router.get('/:id', function(req, res, next) {
    var id = req.params.id
    models.Foo.findById(id)        
        .lean().exec(function (err, results) {
        if (err) return console.error(err)
        try {
            console.log(results)            
        } catch (error) {
            console.log("errror getting results")
            console.log(error)
        } 
    })
})

In Mongo DB your query would be

{_id:ObjectId('5c09fb04ff03a672a26fb23a')}


回答3:

One solution is to use mongoose.ObjectId()

const Model = require('./model')
const mongoose = require('mongoose')

Model.find({ id: mongoose.ObjectId(userID) })

It works, but it is weird because we are using id instead of _id



回答4:

I got into this scenario too. This was how I solved it;

  • According to the mongoose documentation, you need to tell mongoose to return the raw js objects, not mongoose documents by passing the lean option and setting it to true. e.g
Adventure.findById(id, 'name', { lean: true }, function (err, doc) {});

in your situation, it would be

Story.findById(topic.storyId, { lean: true }, function(err, res) {
    logger.info("res", res);
    assert.isNotNull(res);
});


回答5:

Try this

 Story.findOne({_id:"572b19509dac77951ab91a0b"}, function(err, story){
                if (err){
                    console.log("errr",err);
                    //return done(err, null);
                }else{
                    console.log(story);
                }

 });