mongo 可以将文档 prop 中的 JSON 集成到查询中吗?

问题描述 投票:0回答:1

我们在 mongo 中有一些文档,本质上是保存的过滤器,由

name
字符串和
query
JSON 以及一些其他属性组成,例如:

{
  name: "myFilter",
  query: { prop1: "val1", prop2: "val2" },
  groupId: 'xxxyyy'
}

我想要做的是拥有一个应用每个过滤器查询的聚合,这样我们就可以找到哪些过滤器具有匹配项,而无需单独获取和执行每个过滤器。

我得到的最接近的是:

$lookup {
  from: "users",
  localField: "groupId",
  foreignField: "groupId",
  as: "users",
  let: {
    q: "$query",
  },
  pipeline: [
    { $match: { $expr: "$$q" } },
}

问题是,这每次都会匹配所有用户,我认为是因为

$$q
被解释为 json blob,而
$expr
将其视为真实的,而不将其解析为查询的一部分。如果将
"$$q"
替换为
{foo: "bar"}
"foo"
true
,我会得到相同的结果。

我需要的是一个

exec()
函数的等价物,它将使 mongo 实际上处理这个 JSON,就像它已被输入到管道定义中一样。

认识到这可能存在安全问题,有人知道这是否可能吗?


根据请求

编辑,添加示例文档和预期输出。

首先,我忽略了在上面的 Filter 示例中包含

groupId
属性,现在我已经更正了。 groupId 只是将用户分成大群组的一种方法,然后我们使用过滤器对其进行细分。

这是一个完整的示例:

过滤器:

[
  {
    name: "malesOver20",
    query: { gender: "M", age: { $gte: 21 } },
    groupId: "xxxyyy"
  },
  {
    name: "allUnder21",
    query: { age: { $lt: 21 } },
    groupId: "xxxyyy"
  }
]

用户:

[
  {
    name: "Joe Schmoe",
    gender: "M",
    age: 30,
    groupId: 'xxxyyy'
  },
  {
    name: "Kerry Berry",
    gender: "F",
    age: 19,
    groupId: 'xxxyyy'
  },
  {
    name: "Sanjay Manjay",
    gender: "M",
    age: 21,
    groupId: 'xxxyyy'
  }
  {
    name: "Jimmy Pimmy",
    gender: "M",
    age: 8,
    groupId: 'aaabbb'
  }
]

通过将这样的过滤器应用到过滤器集合...

[
  { 
    $lookup: {
      from: "users",
      localField: "groupId",
      foreignField: "groupId",
      as: "users",
      let: {
        q: "$query",
      },
      pipeline: [
        { $match: { $expr: "$$q" } },
      ]
    }
  }
]

我正在尝试得到这样的结果:

[
  {
    name: "malesOver20",
    query: { gender: "M", age: { $gte: 21 } },
    groupId: "xxxyyy",
    users:
      [
        { name: "Joe Schmoe", gender: "M", age: 30, groupId: "xxxyyy" },
        { name: "Sanjay Manjay", gender: "M", age: 21, groupId: "xxxyyy" },
      ],
  },
  {
    name: "allUnder21",
    query: { age: { $lt: 21 } },
    groupId: "xxxyyy",
    users: [{ name: "Kerry Berry", gender: "F", age: 19, groupId: "xxxyyy" }],
  },
]

通常,该管道中会应用更多过滤器,但这是我们陷入困境的部分。我希望这有助于澄清事情!

mongodb mongodb-query
1个回答
0
投票

您可以通过使用 $facet 在 2 个查询中实现此变体。尝试将这段代码转换为您选择的语言。

const filters = db.filters.find();
let facetStage = { $facet: {} };
for (let i = 0; i < filters.length; i++) {
   facetStage['$facet'][filters[i].name] = [{ $match: filters[i].query }, { $match: { groupId: filters[i].groupId } }]; // Add more stages here
}
const pipeline = [facetStage];
const users = db.users.aggregate(pipeline);

在这段代码中,我们首先找到所有的过滤器。然后我们循环它们以创建一个

$facet
阶段。在此阶段,我们存储用户,在不同的键(过滤器名称本身)下匹配不同的过滤器。然后我们在
users
集合上运行此管道。

这将为您提供以下格式的输出:

{
  malesOver20: [
        { name: "Joe Schmoe", gender: "M", age: 30, groupId: "xxxyyy" },
        { name: "Sanjay Manjay", gender: "M", age: 21, groupId: "xxxyyy" },
      ],
  allOver21: [{ name: "Kerry Berry", gender: "F", age: 19, groupId: "xxxyyy" }]
}
© www.soinside.com 2019 - 2024. All rights reserved.