猫鼬自己填充自定义查询
Posted
技术标签:
【中文标题】猫鼬自己填充自定义查询【英文标题】:mongoose own populate with custom query 【发布时间】:2018-08-03 06:25:33 【问题描述】:我正在尝试在 mongoose 中创建自定义查询方法 - 类似于 mongoose 的 populate() 函数。我有以下两个简单的模式:
const mongoose = require('mongoose')
const bookSchema = new mongoose.Schema(
title: String,
author: type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Author'
, versionKey: false)
const authorSchema = new mongoose.Schema(
name: String
, versionKey: false)
现在,我要检索作者信息以及作者所写的书籍。据我所知,猫鼬提供了自定义查询,因此我的想法是编写一个自定义查询函数,例如:
authorSchema.query.populateBooks = function ()
// semi-code:
return forAll(foundAuthors).findAll(books)
现在,要获取所有作者和所有书籍,我可以简单地运行:
authorModel.find().populateBooks(console.log)
这应该是这样的:
[ name: "Author 1", books: ["Book 1", "Book 2"], name: "Author 2", books: ["Book 3"] ]
不幸的是,它不起作用,因为我不知道如何访问之前在我的 populateBooks 函数中选择的作者列表。我在自定义查询功能中需要的是之前选择的文档的集合。 例如,authorModel.find() 已经返回了作者列表。在 populateBooks() 中,我需要遍历此列表以查找所有作者的所有书籍。任何人都知道我可以如何访问这个集合,或者是否有可能?
【问题讨论】:
【参考方案1】:populate:“填充是用其他集合中的文档自动替换文档中指定路径的过程”(来自我链接的文档)。
根据您的问题,您不是在寻找人口。您的查询是一个简单的查询(以下代码是为了实现您最后给出的示例结果。请注意,您的 books 字段的值是一个字符串数组,我假设这些是标题)。另外,请注意以下代码将适用于您已经提供的模型,但这是一个糟糕的实现,我建议反对 - 出于多种原因:效率、优雅、潜在错误(例如,具有相同姓名的作者),见代码后的注释:
Author.find(, function(err, foundAuthors)
if (err)
console.log(err); //handle error
//now all authors are objects in foundAuthors
//but if you had certain search parameters, foundAuthors only includes those authors
var completeList = [];
for (i=0;i<foundAuthors.length;i++)
completeList.push(name: foundAuthors[i].name, books: []);
Book.find().populate("author").exec(function(err, foundBooks)
if (err)
console.log(err); //handle err
for (j=0;j<foundBooks.length;j++)
for (k=0;k<completeList.length;k++)
if (completeList[k].name === foundBooks[j].author.name)
completeList[k].books.push(foundBooks[j].title);
//at this point, completeList has exactly the result you asked for
);
);
但是,正如我所说,我建议不要使用此实现,这是基于您已经提供的代码而没有更改它。
我建议更改您的作者架构以包含书籍属性:
var AuthorSchema = new mongoose.Schema(
books: [
type: mongoose.Schema.Types.ObjectId,
ref: "Book"
]
//all your other code for the schema
);
并将所有书籍添加到各自的作者。这样,您需要做的就是获取一组对象,每个对象都包含一个作者,他的所有书籍都是一个查询:
Author.find().populate("books").exec(function(err, foundAuthors)
//if there's no err, then foundAuthors is an array of authors with their books
);
这比我之前给出的可能的解决方案更简单、更高效、更优雅和更有效,基于您已经存在的代码而不需要更改它。
【讨论】:
感谢您的想法。在推荐的实现中,我保存了两次引用,这在我看来不是一个好方法,而且 BSON 大小限制了实现。作者/书籍模式是为了说明问题。实际上,我目前正在生成 2000 个(在年底增加并预计 5000 个)新条目,这相当于每天 2000 个新书。因此,每位作者的书籍数量在近 2 年后都在增长并达到 16 MB。所以,数组实现是不合适的。 好吧,那么你可以使用第一种方法。可以通过在数组的对象(author: "name", books: [] 对象)中包含作者 _ids 来解决相同的作者姓名问题(如果存在的话),然后使用搜索正确的索引_id 而不是名称。这也将消除对书籍查询使用填充方法的需要 我发现了另一个更好的选择,使用 mongoose 4.5 中引入的 virtuals,请参阅:mongoosejs.com/docs/populate.html#populate-virtuals 嗯,不知道。很好的发现以上是关于猫鼬自己填充自定义查询的主要内容,如果未能解决你的问题,请参考以下文章