英文:
How to skip removed ref while using populate() in Mongoose?
问题
以下是翻译好的内容:
有一个名为MyCollection
的模式,其中包括:
...
author: {
type: mongoose.Schema.Types.ObjectId,
required: true, // 与false相同
ref: 'Author'
},
...
以及以下代码:
MyCollection
.find(filter, '_id author text')
.populate('author', '_id name')
.exec(),
如果从Authors
集合中删除了带有author
的文档,上述的populate方法会抛出以下错误:
无法读取null的属性(读取'_id')
问题是:如何配置populate()以忽略已删除的引用并简单地返回不带author
字段的文档?
英文:
There is a MyCollection
schema with:
...
author: {
type: mongoose.Schema.Types.ObjectId,
required: true, // the same with false
ref: 'Author'
},
...
And the code:
MyCollection
.find(filter, '_id author text')
.populate('author', '_id name')
.exec(),
If the document with author
was removed from Authors
collection, the populate method above throws the following error:
> Cannot read properties of null (reading '_id')
The question is: How can populate() be configured to ignore removed ref's and simply return the document without the author
field?
答案1
得分: 1
我认为忽略已删除的引用并不是一个好主意。如果子文档 author
已被删除,最好的做法是删除引用。Mongoose 的默认行为是在没有文档时返回 null,这就是您收到的错误消息的原因。Mongoose 为您提供了两个辅助方法来检查字段是否已填充。您可以尝试包含以下内容:
// 如果已填充 author,则返回一个真值
MyCollection.populated('author');
// 取消填充 author
MyCollection.depopulate('author');
然而,我建议您重构您的代码,以便在从作者集合中删除文档时传递已删除文档的 author._id
,以便可以从 MyCollection
中删除它。类似这样:
const deletedAuthor = await authorModel.findByIdAndDelete(authorid);
const myCollection = await myCollectionModel.findById(parentId);
myCollection.author.pull(authorid);
await myCollection.save();
另外,您不需要在 .populate('author', '_id name')
投影中包括 _id
,因为根据文档 ,_id
字段默认返回匹配的文档。
您可以在查询后使用基本 JavaScript 删除 null 字段,但您需要将 exec()
更改为 lean()
方法,以便返回 POJO,像这样:
const myCollection = await MyCollection
.find(filter, '_id author text')
.populate('author', '_id name')
.lean();
const myCollectionFiltered = myCollection.map((doc) => {
if (doc.author === null) {
delete doc.author;
}
return doc;
});
现在 `myCollectionFiltered` 不包含作者的 null 值。
英文:
I don't think ignoring removed refs is a good idea. It would be better to remove the ref if the subdocument author
has been deleted. The Mongoose default behaviour is to return null when there's no document, hence the error message you received. Mongoose provides you with two helper methods to check if the field is populated. You could try to incorporate:
// Returns a truthy value if author populated
MyCollection.populated('author');
// Make author not populated anymore
MyCollection.depopulate('author');
However, I would suggest you refactor your code so that when a document from author collection is deleted you pass the author._id
of the deleted document so that it can be pulled from the MyCollection
. Something like:
const deletedAuthor = await authorModel.findByIdAndDelete(authorid);
const myCollection = await myCollectionModel.findById(parentId);
myCollection.author.pull(authorid);
await myCollection.save();
Also, you don't need to include _id
in your .populate('author', '_id name')
projection because according to the docs the _id
field is returned as default on matching documents.
You can remove null fields after your query using basic JavaScript but you need to change exec()
to the lean()
method so that POJO are returned like so:
const myCollection = await MyCollection
.find(filter, '_id author text')
.populate('author', '_id name')
.lean();
const myCollectionFiltered = myCollection.map((doc)=>{
if(doc.author === null){
delete doc.author;
}
return doc;
});
Now myCollectionFiltered
contains no null values for author.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论