mongoose#populate 在数组内的嵌套对象中返回 null

Posted

技术标签:

【中文标题】mongoose#populate 在数组内的嵌套对象中返回 null【英文标题】:mongoose#populate returns null in nested object inside array 【发布时间】:2017-11-17 23:48:18 【问题描述】:

我有一个 mongoDB 数据库,它是使用仅使用 node.js mongoDB 驱动程序而不使用 mongoose 的脚本生成的。稍后,在应用程序中,我想使用 mongoose 加载文档并自动填充引用;然而,这只会返回null

想象一个包含子项的任务,每个子项都有一个标题和一个指定的人。在这种情况下,分配的人员是我想要填充的引用,因此该引用位于任务模式中数组内的对象中。

下面的代码(需要npm install mongodb mongoose)重现了这个问题(注意,如果你已经有一个名为test的本地数据库,它会破坏一个本地数据库):

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

预期的输出将是

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

我已经使用 mongo shell 验证了两个 _ids 实际上匹配:

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

尝试填充person 时我做错了什么?我正在使用 mongoose 4.10.6 和 mongodb 2.2.28。

【问题讨论】:

注意:在populate 调用之后添加.exec() 也不起作用,使用回调代替await 也不起作用。 现在也在猫鼬上以issue #5367 的身份打开。 【参考方案1】:

这个问题的答案在于集合名称mongoose自动从模型Person推断是people而不是persons

可以通过在第一部分写入people 集合或强制猫鼬使用集合名称persons 来解决问题:

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

无论如何,mongoose 计划删除集合名称中的复数形式,请参阅 Github 上的 #1350。

【讨论】:

以上是关于mongoose#populate 在数组内的嵌套对象中返回 null的主要内容,如果未能解决你的问题,请参考以下文章

mongoose 怎么插入嵌套数组

合并嵌套在数组 mongoose 中的对象内的 $lookup 值

Mongoose:嵌套级别的多个填充

Mongoose Populate 返回空数组

Mongoose Populate 返回空数组

Mongoose populate() 返回空数组