如何为复杂结构编写高效的 mongo 查询

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

我使用express/nodejs(没有mongoose)和mongodb作为我的数据库。我有一个集合Pages,看起来像这样

{
  _id: ..
  Urls: [
    {
      IncomingUrl: "/test/test1",
      Status: "active",
    },
    {
      IncomingUrl: "/test/test2",
      Status: "active",
    }
  ],
  DraftUrls: [
    // same structure as Urls
  ] 
  //other fields which arent related to the ques
}

现在,在创建页面时,我正在查看此集合,以查找我在请求正文中提供的 urls 数组中是否有任何 url 已存在于任何现有页面文档中。

并且 如果存在重复的网址,则提供重复网址的列表作为响应。

现在我面临的问题是,如果我只需要获取计数,我可以使用像这样的查找过滤器

const filter = { $or: [
  { "Urls.IncomingUrl": { $in: urls } },
  { "DraftUrls.IncomingUrl": { $in: urls } }
] }

然后使用类似的查询

db.collection(PageCollection).find(filter).countDocuments();

它会给出重复网址的数量

但就我而言,我需要获取重复的网址而不是计数,所以如果我使用这样的东西

const duplicateUrlPages = db.collection(PageCollection).find(filter).toArray();

然后对 url 和重复的 UrlPages 运行嵌套的 for 循环,那么成本太高了。

有人可以建议我如何有效地获取任何页面文档中已存在于其 Urls.IncomingUrl 或 DraftUrls.IncomingUrl 下的输入 url 中的 url 列表

示例:

假设我的数据库中有2个这样的文档

Document1: {
  // ....
  Urls: [ 
    { IncomingUrl: "test1", status: "active" }, 
    // ... 
  ],
  DraftUrls: [
    { IncomingUrl: "test2", status: "inactive" },
    // ...
  ]
}

Document2: {
  // ....
  Urls: [ 
    { IncomingUrl: "test4", status: "active" }, 
    // ... 
  ],
  DraftUrls: [
    { IncomingUrl: "test10", status: "inactive" },
    // ...
  ]
}

我将主体提供给 POST 请求控制器函数作为

{
  // ...
  urls: ["test1", "test2", "test3", "test4"]
}

然后我想要一个响应数组,例如:

["test1", "test2", "test4"]

由于 test1、test2 和 test4 已经存在

node.js mongodb mongodb-query
1个回答
0
投票

这个聚合管道对我有用 但我想知道我是否可以优化这个大管道

const pipeline = [
{ $match: matchFilter },
{
  $project: {
    allUrls: {
      $concatArrays: [
        { $ifNull: ['$Urls', []] },
        { $ifNull: ['$DraftUrls', []] }
      ]
    }
  }
},
{ $unwind: '$allUrls' },
{
  $match: {
    'allUrls.IncomingUrl': { $in: urls }
  }
},
{
  $group: {
    _id: '$allUrls.IncomingUrl',
    count: { $sum: 1 }
  }
},
{
  $match: {
    count: { $gt: 0 }
  }
},
{
  $project: {
    _id: 0,
    IncomingUrl: '$_id'
  }
}
];

const duplicateUrls = await collection.aggregate(pipeline).toArray();

return duplicateUrls.map(doc => doc.IncomingUrl);
© www.soinside.com 2019 - 2024. All rights reserved.