查询包含(或不包含)嵌套文档数组(正在填充)但随后匹配特定条件的文档

Query documents containing (or not) array of nested documents (being populated) but then matching a certain criteria

在标记为“已回答”(或类似的东西)之前请仔细阅读(不仅仅是标题)因为我真的研究了很长时间还没有找到解决方案(我发现了有关查询嵌套数组 objects 的问题,但没有找到需要填充的嵌套数组文档)。

我正在使用最新版本的 NodeJS 和 Mongoose。

为了说明,我将使用这两个模型来帮助描绘我的目标:

// Sections
const mongoose = require('mongoose');
var Schema = mongoose.Schema;

const sectionSchema = new Schema({
  _id:          Schema.Types.ObjectId,
  name:         { type: String, required: [true, 'Name is required.']},
});

module.exports = mongoose.model('Section', sectionSchema);

并且:

// Departments
const mongoose = require('mongoose');
var Schema = mongoose.Schema;

const departmentSchema = new Schema({
  _id:          Schema.Types.ObjectId,
  name:         { type: String, required: [true, 'Name is required.']},
  sections:     [{ type: Schema.Types.ObjectId, ref: 'Section' }]
});

module.exports = mongoose.model('Department', departmentSchema);

考虑一下我将这些存储在数据库中:

// Departments
_id: ObjectId("61b0f1971ad3890000000001")
name: "Department 1",
sections: [ObjectId("61b26a3fb756a1000000000b"), ObjectId("61b26a3fb756a1000000000c")]

_id: ObjectId("61b0f1971ad3890000000002")
name: "Department 2",
sections: [ObjectId("61b26a3fb756a1000000000a"), ObjectId("61b26a3fb756a1000000000c")]

_id: ObjectId("61b0f1971ad3890000000003")
name: "Department 3",
sections: []

_id: ObjectId("61b0f1971ad3890000000004")
name: "Department 4",
sections: [ObjectId("61b26a3fb756a1000000000b")]


// Sections
_id: ObjectId("61b26a3fb756a1000000000a")
name: "Section A"

_id: ObjectId("61b26a3fb756a1000000000b")
name: "Section B"

_id: ObjectId("61b26a3fb756a1000000000c")
name: "Section C"

现在,我要做的是获取不包含部分或名称为“A 部分”的部分的部门(来自前端的文本作为过滤器)。

Department.find(criteria).select('name').populate('sections').then(results => {
    console.log('Departments: ', results.map(r => r.name));
});


// Should print:
Departments: [ Department 2, Department 3 ]

对于标准,我尝试了很多不同的方法,但 none 到目前为止似乎都有效(我总是得到零结果)。下面一个例子:

const criteria = { 
  $or: [
    { 'sections': [] },
    { 'sections': { '$elemMatch': { name: 'Section A' }}},
  ]
};

我认为这是因为 criteria 在查询填充数组之前进行了测试。如果这是正在发生的事情,那么最好的解决方法是什么?我想避免分别查询两个文档然后匹配结果。 应该有办法一次性做到这一点。有任何想法吗?提前致谢。

让我们看看您的查询。 您要查找节 [] 或节名称为 'Section A' 的文档。但是在您的 Department 模型中,您只是保存了每个部分的 id。您无法访问 populating.so 之前提交的名称,您需要根据部分 ID 查找文档。 您可以像下面这样更改条件。

    const criteria = {
    $or: [
        { 'sections': [] },
        { 'sections': mongoose.Types.ObjectId("61b26a3fb756a1000000000a") }
    ]
};

很明显,您无法访问填充前填写的名称。您也可以对填充进行过滤,但我没有找到涵盖这两种情况的解决方案。您还可以阅读 populate documentations.

一种方法是获取所有文档并填充它们,然后实施过滤器,但我认为这不是一个好方法。

//Fetch and populate all documents
const departments = await Department.find({
}).populate({
    path: 'sections',
    select: 'name',
}).exec();

let res = [];
departments.forEach(department => {
    //Select departments which has "Section A" or has not any section
    if (department.sections.some(section => section.name === "Section A") || department.sections.length === 0) {
        res.push(department);
    }
});

经过详尽的测试和研究,我得出结论,仅通过操纵填充 criteria 的内容无法一次性获得预期结果 。 =14=]

querying documents with nested/embedded array of other documents 提供的最接近的 MongoDB 文档不涉及 populate

因此,current/next 实现目标的最佳方法(打印不包含部分的部门或 'Section A' 而没有提供 section._id 但仅 section.name ) 是:

Section.find({ name: 'Section A' }).then(sections => {
  Department.find({ 
    $or: [
      { 'sections': [] },
      { 'sections': { $in: sections }},
    ]
  }).then(departments => console.log('Departments: ', results.map(r => r.name));
  // Will print: Departments: [ Department 2, Department 3 ]
});