MongoDB группировка агрегированного запроса с отношением - PullRequest
1 голос
/ 20 марта 2020

Допустим, у меня есть следующие документы в коллекции ассоциация :

{
    "id" : 1,
    "parentId" : 1,
    "position" : {
        "x" : 1,
        "y" : 1
    },
    "tag" : "Beta"
},
{
    "id" : 2,
    "parentId" : 2,
    "position" : {
        "x" : 2,
        "y" : 2
    },
    "tag" : "Alpha"
},
{
    "id" : 3,
    "parentId" : 1,
    "position" : {
        "x" : 3,
        "y" : 3
    },
    "tag" : "Delta"
},
{
    "id" : 4,
    "parentId" : 1,
    "position" : {
        "x" : 4,
        "y" : 4
    },
    "tag" : "Gamma"
},
{
    "id" : 5,
    "parentId" : 2,
    "position" : {
        "x" : 5,
        "y" : 6
    },
    "tag" : "Epsilon"
}

Я хотел бы создать агрегированный запрос для получения следующего результата:

{
    "_id" : 2,
    "position" : {
        "x" : 2,
        "y" : 2
    },
    "tag" : "Alpha",
    "children" : [
        {
            "position" : {
                "x" : 5,
                "y" : 6
            },
            "tag" : "Epsilon"
        }
    ]
},
{
    "_id" : 1,
    "position" : {
        "x" : 1,
        "y" : 1
    },
    "tag" : "Beta"
    "children" : [
        {
            "position" : {
                "x" : 3,
                "y" : 3
            },
            "tag" : "Delta"
        },
        {
            "position" : {
                "x" : 4,
                "y" : 4
            },
            "tag" : "Gamma"
        }
    ]
}

Однако мне удалось создать только следующий группирующий запрос, который помещает «все связанные» документы в массив дочерних элементов:

db.association.aggregate([{
   $group  : {
       _id : "$parentId",
       children : {
           $push :  {
                   position : "$position",
                   tag :"$tag"
               }
       }
   }
}])

Я не знаю, как отфильтровать позицию "and" tag "указывает c на" родительские "точки и помещает их на верхний уровень.

Ответы [ 2 ]

2 голосов
/ 21 марта 2020

Несмотря на то, что ответ Валижона работает, его нужно предварительно отсортировать. Вот решение без необходимости сортировки, но с использованием этапа graphLookup (который идеально подходит для достижения того, что вам нужно)

db.collection.aggregate([
  {
    $graphLookup: {
      from: "collection",
      startWith: "$id",
      connectFromField: "id",
      connectToField: "parentId",
      as: "children",

    }
  },
  {
    $match: {
      $expr: {
        $gt: [
          {
            $size: "$children"
          },
          0
        ]
      }
    }
  },
  {
    $addFields: {
      children: {
        $filter: {
          input: "$children",
          as: "child",
          cond: {
            $ne: [
              "$id",
              "$$child.id"
            ]
          }
        }
      }
    }
  }
])
  • На первом этапе выполняется работа.
  • Второй здесь, чтобы отфильтровать документы, которые не имеют детей.
  • Третий присутствует только для удаления родителя из дочернего массива. Но если вы можете удалить ссылку на себя в родительском элементе, этот последний этап больше не понадобится.

Вы можете попробовать его здесь

1 голос
/ 20 марта 2020

Убедившись, что документы отсортированы (родитель - дети 1 - дети 2 ... - дети n ), мы можем объединить grouped document с 1-м ребенком (то есть parent). На последнем шаге нам нужно удалить parent из children массива.

Попробуйте это:

db.association.aggregate([
  {
    $sort: {
      parentId: 1,
      id: 1
    }
  },
  {
    $group: {
      _id: "$parentId",
      children: {
        $push: {
          position: "$position",
          tag: "$tag"
        }
      }
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          "$$ROOT",
          {
            $arrayElemAt: [
              "$children",
              0
            ]
          }
        ]
      }
    }
  },
  {
    $addFields: {
      children: {
        $slice: [
          "$children",
          1,
          {
            $size: "$children"
          }
        ]
      }
    }
  }
])

MongoPlayground

...