MongoDB 使用 mongoose 填充一个字段并计算嵌套布尔字段中的总 'true' 个值

MongoDB populate a field and count total 'true' values in nested boolean fields using mongoose

我有两个mongo结构文件

链接文档

{
  "_id": {
    "$oid": "6002d2d627925c4194a15a94"
  },
  "visit_count": 20,
  "password": null,
  "password_protected": false,
  "description": null,
  "analytics": [
    {
      "$oid": "6002d568e9c7d24d34413492"
    },
    {
      "$oid": "6002d612464785401824a782"
    }
  ],
  "alias": "g",
  "short_url": "https://reduced.me/g",
  "long_url": "https://google.com",
  "created": {
    "$date": "2021-01-16T11:49:42.517Z"
  },
  "__v": 2
}

分析文档

[
  {
    "_id": {
      "$oid": "6002d568e9c7d24d34413492"
    },
    "os": {
      "windows": true,
      "linux": false,
      "mac": false,
      "android": false
    },
    "browser": {
      "opera": false,
      "ie": false,
      "edge": false,
      "safari": false,
      "firefox": true,
      "chrome": false
    },
    "details": {
      "os": "Windows 10.0",
      "browser": "Edge",
      "version": "87.0.664.75",
      "platform": "Microsoft Windows",
      "source": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75"
    },
    "__v": 0
  },
  {
    "_id": {
      "$oid": "6002d612464785401824a782"
    },
    "os": {
      "windows": true,
      "linux": false,
      "mac": false,
      "android": false
    },
    "browser": {
      "opera": false,
      "ie": false,
      "edge": true,
      "safari": false,
      "firefox": false,
      "chrome": false
    },
    "details": {
      "os": "Windows 10.0",
      "browser": "Edge",
      "version": "87.0.664.75",
      "platform": "Microsoft Windows",
      "source": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75"
    },
    "__v": 0
  }
]

我想做的是,用 analytics 文档中的值填充 links 文档中的 analytics 数组,然后还总结了 osbrowser 对象中每个字段的 true 布尔值的计数。我正在寻找的输出结构是 -

{
    "_id": null,
    "visit_count": 20,
    "password_protected": false,
    "description": null,
    "alias": "g",
    "short_url": "https://reduced.me/g",
    "long_url": "https://google.com",
    "created": "2021-01-16T11:49:42.517Z",
    "analytics": {
        "os": {
            "windows": 2,
            "linux": 0,
            "mac": 0,
            "android": 0
        },
        "browser": {
            "opera": 0,
            "ie": 0,
            "edge": 1,
            "safari": 0,
            "firefox": 1,
            "chrome": 0
        }
    }
}

这里,例如,windows:2 显示在整个文档中 windows 的值为 true 的次数。

目前我是这样做的

const analytics = await LinkModel.aggregate([
        { $match: { short_url: req.body.short_url } },

        {
            $lookup: {
                from: 'analytics',
                localField: 'analytics',
                foreignField: '_id',
                as: 'analytics',
            },
        },
        { $unwind: '$analytics' },
        {
            $group: {
                _id: null,

                visit_count: { $first: '$visit_count' },
                password_protected: { $first: '$password_protected' },
                description: { $first: '$description' },
                alias: { $first: '$alias' },
                short_url: { $first: '$short_url' },
                long_url: { $first: '$long_url' },
                created: { $first: '$created' },

                windows: {
                    $sum: { $cond: ['$analytics.os.windows', 1, 0] },
                },
                linux: {
                    $sum: { $cond: ['$analytics.os.linux', 1, 0] },
                },
                mac: {
                    $sum: { $cond: ['$analytics.os.mac', 1, 0] },
                },
                android: {
                    $sum: { $cond: ['$analytics.os.android', 1, 0] },
                },
                opera: {
                    $sum: { $cond: ['$analytics.browser.opera', 1, 0] },
                },
                ie: {
                    $sum: { $cond: ['$analytics.browser.ie', 1, 0] },
                },
                edge: {
                    $sum: { $cond: ['$analytics.browser.edge', 1, 0] },
                },
                safari: {
                    $sum: {
                        $cond: ['$analytics.browser.safari', 1, 0],
                    },
                },
                firefox: {
                    $sum: {
                        $cond: ['$analytics.browser.firefox', 1, 0],
                    },
                },
                chrome: {
                    $sum: {
                        $cond: ['$analytics.browser.chrome', 1, 0],
                    },
                },
            },
        },
    ])

这确实给出了这样的输出

[{
    "_id": null,
    "visit_count": 20,
    "password_protected": false,
    "description": null,
    "alias": "g",
    "short_url": "https://reduced.me/g",
    "long_url": "https://google.com",
    "created": "2021-01-16T11:49:42.517Z",
    "windows": 2,
    "linux": 0,
    "mac": 0,
    "android": 0,
    "opera": 0,
    "ie": 0,
    "edge": 1,
    "safari": 0,
    "firefox": 1,
    "chrome": 0
}]

它有我需要的所有数据,但结构不正确。我使用 mongoose 作为 ORM。任何帮助,将不胜感激。谢谢。

你可以使用$addFields得到你想要的输出

db.collection.aggregate([
  {
    $addFields: {
      "analytics": {
        "os": {
          "windows": "$windows",
          "linux": "$linux",
          "mac": "$mac",
          "android": "$android"
        },
        "browser": {
          "opera": "$opera",
          "ie": "$ie",
          "edge": "$edge",
          "safari": "$safari",
          "firefox": "$firefox",
          "chrome": "$chrome"
        }
      },
      "windows": "$$REMOVE",
      "linux": "$$REMOVE",
      "mac": "$$REMOVE",
      "android": "$$REMOVE",
      "opera": "$$REMOVE",
      "ie": "$$REMOVE",
      "edge": "$$REMOVE",
      "safari": "$$REMOVE",
      "firefox": "$$REMOVE",
      "chrome": "$$REMOVE"
    }
  }
])

工作Mongo playground