【问题标题】:How to group two collections in one query with MongoDB or Mongoose如何使用 MongoDB 或 Mongoose 在一个查询中对两个集合进行分组
【发布时间】:2020-10-25 15:21:34
【问题描述】:

我有这样的页面。数据来自我的 MongoDB 服务器。

首先,我创建用户集合并放置这些用户数据。但是我添加了 Counter 集合,因为我想显示他们的 View Count。

每个用户有多个页面,View Count数据是Counter数据的总和。

用户集合看起来像这样,我只需要登录,id(唯一)数据。

用户收藏

{
    "_id": {
        "$oid": "5f7e92b88dc8f64cb4e6c2c0"
    },
    "login": "mojombo",
    "id": 1,
    "avatar_url": "https://avatars0.githubusercontent.com/u/1?v=4",
    "url": "https://api.github.com/users/mojombo",
    "html_url": "https://github.com/mojombo",
    "type": "User",
    "site_admin": "false",
    "name": "Tom Preston-Werner",
    "company": null,
    "blog": "http://tom.preston-werner.com",
    "location": "San Francisco",
    "email": "tom@mojombo.com",
    "hireable": null,
    "bio": null,
    "created_at": {
        "$date": "2007-10-20T05:24:19.000Z"
    },
    "updated_at": {
        "$date": "2020-09-22T15:50:44.000Z"
    },
    "registerDate": {
        "$date": "2020-10-08T04:16:56.459Z"
    },
    "__v": 0
}

计数器集合

{
    "_id": {
        "$oid": "5f8e5bde9054ba2477dc2c57"
    },
    "repoName": "ale",
    "repoNumber": 171780764,
    "userName": "technicalpickles",
    "userNumber": 159,
    "viewDate": "2020-10-20",
    "count": 1
}

在 Counters 集合中,我只需要 userName, count 字段来计算计数器数据。

所以我尝试了循环和聚合方法,但问题是用户数据太多,所以我必须向服务器发送太多查询。 (如果我有 10000 个用户数据,我必须发送 10000 个请求)所以,我不能使用 for 循环方法。

router.get(`/sitemap/0`, async (req, res, next) => {
  let name;
  let dataArray = [];
  let pageNumber = (Number(req.params.page) * 10000); // Current Page Number
  let nextPage = (Number(req.params.page) + 1) * 10000; // Next Page Number
  let pageResult; // Page Result
  try {
    let users = await User.find({}, 'login id').limit(1000)
    for (let i = 0; i < 1000; i++) {
      name = users[i].login
      let counters = await Counter.aggregate([{
          $match: {
            id: users.id,
            userName: users[i].login
          }
        },
        {
          $group: {
            _id: `${users[i].login}`,
            count: {
              $sum: "$count"
            }
          }
        }
      ])
      dataArray.push(counters)
      console.log(counters)
    }
    console.log(dataArray)

  } catch (e) {
    // throw an error
    throw e;
  }
  res.render("sitemap", {
    dataArray
  })
});

代码结果

所以我想发送单个查询,我认为应该使用“聚合”方法。但没有'for循环'。

我想加入Users collection和Counters collection,但听说MongoDB和Mongoose没有加入功能。

我只想做出这样的结果。有没有办法让它变成这样?

{
    "_id": {
        "$oid": "5f7e92b88dc8f64cb4e6c2c0"
    },
    "login": "mojombo", --------------Match login with counter collection 'userName' value
    "id": 1,  ------------------------Match id with counter collection 'id' value
    "count": [Sum of counters count data and it should be Number] ------- Only this field is added
    "avatar_url": "https://avatars0.githubusercontent.com/u/1?v=4",
    "url": "https://api.github.com/users/mojombo",
    "html_url": "https://github.com/mojombo",
    "type": "User",
    "site_admin": "false",
    "name": "Tom Preston-Werner",
    "company": null,
    "blog": "http://tom.preston-werner.com",
    "location": "San Francisco",
    "email": "tom@mojombo.com",
    "hireable": null,
    "bio": null,
    "created_at": {
        "$date": "2007-10-20T05:24:19.000Z"
    },
    "updated_at": {
        "$date": "2020-09-22T15:50:44.000Z"
    },
    "registerDate": {
        "$date": "2020-10-08T04:16:56.459Z"
    },
    "__v": 0
}

【问题讨论】:

    标签: javascript node.js mongodb mongoose


    【解决方案1】:
    • $lookup 使用流水线阶段收集计数器,让传递 2 个字段 id, login 以匹配计数器收集
    • $match 两个字段条件
    • $addFields 到 count 计数器数组中计数字段的总和,使用 $reduce 迭代循环和 $add 对计数字段的值求和
    • $skip 用于分页
    • $limit 超过你的文件限制
    let page = 1; // start pagination from first
    let limit = 1000;
    let skip = (page - 1) * limit;
    let users = await User.aggregate([
      {
        $lookup: {
          from: "counters",
          let: {
            id: "$id",
            login: "$login"
          },
          pipeline: [
            {
              $match: {
                $expr: {
                  $eq: ["$userName", "$$login"],
                  $eq: ["$userNumber", "$$id"]
                }
              }
            }
          ],
          as: "count"
        }
      },
      {
        $addFields: {
          count: {
            $reduce: {
              input: "$count",
              initialValue: 0,
              in: { $add: ["$$value", "$$this.count"] }
            }
          }
        }
      },
      { $skip: skip },
      { $limit: limit }
    ])
    

    Playground

    【讨论】:

    • 谢谢!有一个错误的变量名,但我正在修复它!它终于奏效了!我还编辑了新的游乐场代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多