1

I have a mongoDB database which is generated using a script that uses only the node.js mongoDB driver without mongoose. Later on, in the application, I want to use mongoose to load a document and have a reference be populated automatically; however, this only ever returns null.

Imagine a task which contains sub-items which each have a title and an assigned person. The assigned person, in this case, is the reference I want to have populated, so the reference lives in an object inside an array in the task schema.

The following code (requiring npm install mongodb mongoose) reproduces the problem (watch out, it destroys a local database named test if you have one already):

const mongodb = require('mongodb');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

(async () => {
    // Step 1: Insert data. This is done using the mongodb driver without mongoose.
    const db = await mongodb.MongoClient.connect('mongodb://localhost/test');
    await db.dropDatabase();
    await db.collection('persons').insertOne({ name: 'Joe' });

    const joe = await db.collection('persons').findOne({ name: 'Joe' });
    await db.collection('tasks').insertOne({ items: [{ title: 'Test', person: joe._id }] });

    await db.close();

    // ================
    // Step 2: Create the schemas and models.
    const PersonSchema = new Schema({
        name: String,
    });
    const Person = mongoose.model('Person', PersonSchema);

    const TaskSchema = new Schema({
        items: [{
            title: String,
            person: { type: Schema.Types.ObjectId, ref: 'Person' },
        }],
    });
    const Task = mongoose.model('Task', TaskSchema);

    // ================
    // Step 3: Try to query the task and have it populated.
    mongoose.connect('mongodb://localhost/test');
    mongoose.Promise = Promise;

    const myTask = await Task.findOne({}).populate('items.person');

    // :-( Unfortunately this prints only
    // { _id: "594283a5957e327d4896d135", items: [ { title: 'Test', person: null } ] }
    console.log(JSON.stringify(myTask, null, 4));

    mongoose.connection.close();
})();

The expected output would be

{ _id: "594283a5957e327d4896d135", items: [ { title: 'Test', person: { _id: "594283a5957e327d4896d134", name: "Joe" } } ] }

I have verified that the two _ids actually match using mongo shell:

> db.persons.find({})
{ "_id" : ObjectId("594283a5957e327d4896d134"), "name" : "Joe" }
> db.tasks.find({})
{ "_id" : ObjectId("594283a5957e327d4896d135"), "items" : [ { "title" : "Test", "person" : ObjectId("594283a5957e327d4896d134") } ] }

What am I doing wrong when attempting to populate person? I am using mongoose 4.10.6 and mongodb 2.2.28.

2
  • Note: Adding .exec() after the populate call doesn't work either, neither does using a callback instead of await. Commented Jun 15, 2017 at 16:18
  • Also opened as issue #5367 on mongoose now. Commented Jun 15, 2017 at 16:30

1 Answer 1

1

The answer to this problem lies in the fact that the collection name mongoose automatically infers from the model Person is people and not persons.

The problem can be solved either by writing to the people collection in the first part or by forcing mongoose to use the collection name persons:

const Person = mongoose.model('Person', PersonSchema, 'persons');

mongoose plans to remove pluralization in the collection name anyway, see #1350 on Github.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.