dcsan
dcsan

Reputation: 12315

find by _id with Mongoose

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
  }

enter image description here

Upvotes: 31

Views: 113726

Answers (9)

Nevada
Nevada

Reputation: 173

For usage with Schema and _id default mongo Key. Set the typeof _id in the Schema.

const mongoose = require('mongoose');
 
const projectSchema = new mongoose.Schema({
    _id: mongoose.SchemaTypes.ObjectId,
    //Add another field
});
 

const Project = mongoose.model('Project', projectSchema);
module.exports.ProjectsService = class ProjectsService {

    async getProjectById(req, res) {
        try {
            const projectId = req.params.projectId;             
            let project = await Project.find({ "_id": projectId })
            res.json(project);
        } catch (err) {
            throw err
        };
    };
};

Upvotes: 0

Siddiqui Noor
Siddiqui Noor

Reputation: 8006

This is how we do it now:

const { mongoose } = require("mongoose");
YourModel.find({ _id: mongoose.Types.ObjectId("572f16439c0d3ffe0bc084a4") });

Upvotes: 1

Vijay
Vijay

Reputation: 317

models.findById(id)

TRY THIS ONE . REF LINK : https://www.geeksforgeeks.org/mongoose-findbyid-function/

Upvotes: -1

s4f3r71
s4f3r71

Reputation: 46

If _id is the default mongodb key, in your model set the type of _id as this:

_id: mongoose.SchemaTypes.ObjectId

Then usind mongoose you can use a normal find:

YourModel.find({"_id": "5f9a86b77676e180c3089c3d"});

Upvotes: 1

Baraja Swargiary
Baraja Swargiary

Reputation: 459

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

Upvotes: 3

daymorelah
daymorelah

Reputation: 69

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);
});

Upvotes: 0

Lawrence Edmondson
Lawrence Edmondson

Reputation: 167

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')}

Upvotes: 9

JohnnyHK
JohnnyHK

Reputation: 312095

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 }

Upvotes: 24

Manoj Ojha
Manoj Ojha

Reputation: 371

Try this

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

 });

Upvotes: -2

Related Questions