MongoDB заполняет поле и подсчитывает общие «истинные» значения во вложенных логических полях с использованием mongoose

У меня есть два документа монго структуры

ссылки на документ

{
  "_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, а также суммировать количество true логических значений для каждого поля в >os и объекты browser. структура вывода, которую я ищу, -

{
    "_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
}]

у него есть все данные, которые мне нужны, но структура неверна. Я использую мангуста в качестве ORM. Любая помощь будет оценена по достоинству. Спасибо.


person Sumit kolhe    schedule 17.01.2021    source источник


Ответы (1)


Вы можете использовать $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

person varman    schedule 17.01.2021
comment
РЕДАКТИРОВАТЬ-решено с помощью предоставленного вами кода. спасибо за быстрый ответ, но я уже пробовал $addFields. мне нужно добавить его в конвейер или что-то в этом роде? или вы можете дать весь код с агрегацией + $addFields? - person Sumit kolhe; 17.01.2021
comment
Вы опубликовали результат после этапа $group, верно? После этого сделайте это $addFields - person varman; 17.01.2021
comment
Добро пожаловать в stackoverflow и, пожалуйста, посмотрите meta.stackexchange.com/a/5235/618454, чтобы принять отвечать - person varman; 17.01.2021
comment
Я отметил это как принятый ответ. еще одна вещь, в настоящее время я получаю вывод в массиве с одним объектом внутри со всеми данными. любой способ удалить внешний массив и вместо этого просто получить документ? - person Sumit kolhe; 17.01.2021
comment
Я не знаком с мангустом, но вы можете получить первый элемент из массива с помощью javascript. Я знаком с java, в которой есть getUniqueResult(), который дает объект. У мангуста тоже могут быть такие методы - person varman; 17.01.2021
comment
Спасибо. пока я просто очищаю его при возврате ответа клиенту. - person Sumit kolhe; 17.01.2021