mongodb 中具有嵌套数组的多个文档分组

multiple grouping of documents with nested array in mongodb

我有一个文档列表,其中包含这些字段 ID:'int'、类别:'text'、字段:'text',以及项目列表 [{title, value}]

     documents= [
      { "id":"1",
        "category": "education",
        "field": "science",
        "items": [
          {
            "title": "item 1",
            "value": "10"
          },
          {
            "title": "item 2",
            "value": "102"
          },
          {
            "title": "item 4",
            "value": "12"
          }
        ]
      },
      { "id":"2",
        "category": "education",
        "field": "science",
        "items": [
          {
            "title": "item 1",
            "value": "4"
          },
          {
            "title": "item 2",
            "value": "23"
          },
          {
            "title": "item 4",
            "value": "45"
          }
        ]
      },
      { "id":"3",
        "category": "fitness",
        "field": "body",
        "items": [
          {
            "title": "item 1",
            "value": "87"
          },
          {
            "title": "item 5",
            "value": "45"
          },
          {
            "title": "item =3",
            "value": "23"
          }
        ]
      },
 { "id":"4",
    "category": "education",
    "field": "culture",
    "items": [
      {
        "title": "item 1",
        "value": "187"
      },
      {
        "title": "item 5",
        "value": "145"
      },
      {
        "title": "item 3",
        "value": "123"
      }
    ]]

我正在与 mongodb(初学者)合作,我很困惑如何首先按类别对这些文档进行分组,然后按字段,然后按项目的标题将它们的值像列表一样推送到数组中价值观的历史。 期望的结果:

    newDocument=[
    { "newid":"1",
      "category": "education",
      "field": "science",
      "items": [
        {
          "title": "item 1",
          "value": ["10","4"]
        },
        {
          "title": "item 2",
          "value": ["102","23"]
        },
        {
          "title": "item 4",
          "value": ["12", "45"]
        }
      ]
    },
{ "newid":"2",
        "category": "education",
        "field": "culture",
        "items": [
            {
              "title": "item 1",
              "value": ["187"]
            },
            {
              "title": "item 5",
              "value":["145"]
            },
            {
              "title": "item 3",
              "value": ["123"]
            }
          ]
      }
    { "newid":"3",
        "category": "fitness",
        "field": "body",
        "items": [
            {
              "title": "item 1",
              "value": ["87"]
            },
            {
              "title": "item 5",
              "value":["45"]
            },
            {
              "title": "item 3",
              "value": ["23"]
            }
          ]
      }
  ]

可以使用聚合查询,但会影响性能和响应速度,有两种选择,一种使用$unwind,另一种使用$accumulator运算符,

使用 $accumulator:

  • $group 通过 categoryfield
  • $accumulator 做自定义 JavaScript 逻辑和合并项目数组,你可以根据你的要求改进和更新
  • $project 显示必填字段
db.collection.aggregate([
  {
    $group: {
      _id: {
        category: "$category",
        field: "$field"
      },
      items: {
        $accumulator: {
          init: function() { return []; },
          accumulate: function(items1, items2) {
            return items1.concat(items2);
          },
          accumulateArgs: ["$items"],
          merge: function(items1, items2) {
            return items1.concat(items2);
          },
          finalize: function(state) { 
            var items = {}, finalItems = [];
            state.forEach(function(item) {
              if (items[item.title]) {
                items[item.title].value.push(item.value); 
              }
              else {
                item.value = [item.value];
                items[item.title] = item;
              }
            });
            for (var i in items) {
              finalItems.push(items[i]);
            }
            return finalItems; 
          },
          lang: "js"
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      category: "$_id.category",
      field: "$_id.field",
      items: 1
    }
  }
])

使用 $unwind:(不推荐)

  • $unwind解构items数组
  • $group by category, field and item title 并构造数组 if item values
  • $group 通过 categoryfield 并用 titlevalue
  • 构造 items 数组
  • $project 显示必填字段
db.collection.aggregate([
  { $unwind: "$items" },
  {
    $group: {
      _id: {
        category: "$category",
        field: "$field",
        title: "$items.title"
      },
      value: { $push: "$items.value" }
    }
  },
  {
    $group: {
      _id: {
        category: "$_id.category",
        field: "$_id.field"
      },
      items: {
        $push: {
          title: "$_id.title",
          value: "$value"
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      category: "$_id.category",
      field: "$_id.field",
      items: 1
    }
  }
])

Playground