不能用猫鼬做populate()

Cannot do populate() with mongoose

提问人:Tony mpt 提问时间:11/14/2023 更新时间:11/14/2023 访问量:56

问:

我是 MongoDB 和 Mongoose 的新手,我想在两个文档之间执行 populate()。在查阅文档并寻找答案后,我向您寻求帮助。 我有两个模型:

笔记模型

const mongoose = require('mongoose');

const noteSchema = mongoose.Schema({
    _id: mongoose.Schema.Types.ObjectId,
    title: { 
        type: String, 
        required: true 
    },
    color: { 
        type: String, 
        required: true 
    },
    position: { 
        type: Number, 
        required: true 
    },
    isCheckBoxMode: { 
        type: Boolean,
        required: true 
    },
    items: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Item'
    }]
}, {timestamps: true });

const Note = mongoose.model('Note', noteSchema);

module.exports = Note;

项目模型

const mongoose = require('mongoose');

const itemSchema = mongoose.Schema({
    _id: mongoose.Schema.Types.ObjectId,
    text: {
        type: String, 
        required: true
    },
    isCompleted: {
        type: Boolean, 
        required: true
    },
    noteId: { 
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Note',
        required: true
    },
}, {timestamps: true });

const Item = mongoose.model('Item', itemSchema);

module.exports = Item;

在此查询中,我想使用引用 Item 文档的“items”属性检索链接到 noteId 的所有项目的数组。如上所述,我确保在两个文档之间进行引用,一方面使用 items 属性及其 ref Item,另一方面使用 NoteId 属性,其 id 对应于正确的注释并引用 Note 文档。

最好有一个例子。我正在使用 Mongo Atlas 快速部署数据库。我用 Postman 创建了一个 ID 为“6553448ef2c06064f266f785”的注释:

笔记文档

以及两个项目,每个项目引用 noteId “6553448ef2c06064f266f785”:

项目文档

不幸的是,当我使用 populate('items') 发送请求以检索我的项目内容时,我收到一个空数组:

router.get('/:noteId', (req, res, next) => {
    const id = req.params.noteId;
    Note.findById(id)
        .populate('items')
        .exec()
        .then(doc => {
            if (doc) {
                res.status(200).json({
                    notes: doc,
                });
            }else {
                res.status(404).json({message : 'No Valid entry found for provided ID'});
            }
        })
        .catch(err => {
            console.log(err);
            res.status(500).json({error: err});
        });
});

Postman 中的请求和响应

请求

我找到了另一种解决方案,使用“虚拟”,但它不是最优化的解决方案,我害怕失去性能。

const mongoose = require('mongoose');

const noteSchema = mongoose.Schema({
    _id: mongoose.Schema.Types.ObjectId,
    title: { 
        type: String, 
        required: true 
    },
    color: { 
        type: String, 
        required: true 
    },
    position: { 
        type: Number, 
        required: true 
    },
    isCheckBoxMode: { 
        type: Boolean,
        required: true 
    },
}, {timestamps: true });

noteSchema.virtual('items', {
    ref: 'Item',
    localField: '_id',
    foreignField: 'noteId'
});

noteSchema.set('toObject', { virtuals: true });
noteSchema.set('toJSON', { virtuals: true });

const Note = mongoose.model('Note', noteSchema);

module.exports = Note;

对不起,如果我的问题有点愚蠢,但我搜索了很长时间,找不到任何解决方案。提前感谢您的帮助

我试图在 Mongoose 文档以及其他 Stack Overflow 帖子之后链接这两个文档,但没有奏效。此外,我设置了一个有效的“虚拟”,并允许我检索所有项目,但这并未优化。此外,当我使用 POST 路由添加项目时,如果在我的请求中,我也将项目的 id 添加到注释的“items”数组中,则填充有效。 但这也不是一个优化的解决方案。我想在两个“refs”之间做一个简单的填充。

node.js mongoose ref mongoose-populate

评论

0赞 RickN 11/14/2023
如果打开调试,则可以看到 Mongoose 生成的查询。将这些包含在您的问题中可能会有所帮助。

答:

0赞 jQueeny 11/14/2023 #1

您的 Note 架构看起来不错。您有一个属性,该属性已被正确定义为具有相应数组的数组,因此看起来是教科书。itemsmongoose.Schema.Types.ObjectIdref:'Note'

我的建议是将 and 属性显式传递给该方法并采用如下模式:pathmodelpopulateasync/await

router.get('/:noteId', async (req, res, next) => { //< Mark as async
   try{
      const id = req.params.noteId;
      const doc = await Note.findById(id).populate({ //< use await 
         path: 'items', model: Item //< pass in the path and model
      });
      if(!doc){
         return res.status(400).json({
            message : 'No Valid entry found for provided ID'
         });
      }else{
         return res.status(200).json({
            notes: doc,
         });
      } 
   }catch(err){
      console.log(err);
      res.status(500).json({error: err});
   }
});

注意:请确保数组中有值。从指南针屏幕截图中看不清楚,因为数组在显示屏中折叠。最后,你的内在是正确的,你不需要虚拟。ObjectIditemsitems

评论

0赞 Tony mpt 11/14/2023
Ty 为您的回复:)这是个好主意,但不幸的是,它不起作用。尽管使用了该方法并显式传递了 and 属性,但我仍然得到一个空数组。我重新创建了一个,可以肯定的是。但是,确实,为了响应您的注释,我的数组中没有项。每次创建项目时,是否需要在备注上再次发出请求以将项目的 ID 推送到备注中?我以为 Mongoose 会自动在 Item 文档中搜索与注释对应的 noteId。对不起,我不习惯 NoSQL。async/awaitpathmodelnoteitemsobjectIds
0赞 jQueeny 11/14/2023
是的,每当创建新项目时,都需要将项目 ID 添加到 Notes.items 数组中。不幸的是,这不是自动为您完成的。
0赞 Tony mpt 11/14/2023
我以为猫鼬很神奇。一切都清楚了,非常感谢
0赞 jQueeny 11/14/2023
我认为邮政钩子会对你有好处。在 Item 架构上有一个 post 挂钩,将 id 推送到 Notes.items 数组中,在您的情况下是可行的。这就是神奇的部分!save
0赞 Tony mpt 11/14/2023
非常感谢,这个技巧非常有用