Вывод из совокупного массива объектов в ключи документа

1

У меня есть некоторые данные торговли, подобные этому

{
    "_id" : 1498290900.0,
    "trade" : {
        "type" : "Modify",
        "data" : {
            "type" : "bid",
            "rate" : "0.00658714",
            "amount" : "3.82354427"
        },
        "date" : 1498290930291.0,
        "name" : "TLX"
    }
},{
    "_id" : 1498290900.0,
    "trade" : {
        "type" : "Modify",
        "data" : {
            "type" : "ask",
            "rate" : "0.00658714",
            "amount" : "3.82354427"
        },
        "date" : 1498290930291.0,
        "name" : "TLX"
    }
},{
    "_id" : 1498290900.0,
    "trade" : {
        "type" : "Remove",
        "data" : {
            "type" : "ask",
            "rate" : "0.00680891"
        },
        "date" : 1498290931349.0,
        "name" : "TLX"
     }
}

Они исходят от $rewind следовательно, _id является тем же. Хочу, чтобы я хотел сделать следующее, это группировать их на _id поэтому я пытаюсь

{ 
    $group: { 
      _id: {_id: "$_id", name: "$trade.type",dtype: "$trade.data.type"},
        count          : {$sum: 1}
    },
  },{$project: { _id: "$_id._id", type: "$_id.name", count: 1, dtype: "$_id.dtype" } },
  {

      $group: {
          _id: "$_id",
          results: { $push : "$$ROOT" }
          }
  }

Что довольно хорошо, дайте мне ниже

 {
    "_id" : 1498276800.0,
    "results" : [ 
        {
            "count" : 16.0,
            "_id" : 1498276800.0,
            "type" : "Modify",
            "dtype" : "bid"
        }, 
        {
            "count" : 15.0,
            "_id" : 1498276800.0,
            "type" : "Remove",
            "dtype" : "bid"
        }, 
        {
            "count" : 3.0,
            "_id" : 1498276800.0,
            "type" : "Remove",
            "dtype" : "ask"
        }, 
        {
            "count" : 1.0,
            "_id" : 1498276800.0,
            "type" : "Modify",
            "dtype" : "ask"
        }
    ]
}

Но я пытался сделать вывод больше похожим на этот

  {
    "_id" : 1498276800.0,
    "Modify": {
      "bid":{
        "count": 16.0
      },
      "ask": {
        "count": 1.0
      }
    },
    "Remove": {
      "bid":{
        "count": 15.0
      },
      "ask": {
        "count": 3.0
      }
    }
  }

Но никакое количество игр с $projections привело меня близко.

Может ли кто-нибудь указать мне в правильном направлении, пожалуйста?

Благодарю.

ОБНОВИТЬ

Исключая последний этап конвейера, это пример документов с хорошим предложением/спросом на тип, готовый к группировке с помощью _id.

{
    "_id" : {
        "_id" : 1498276800.0,
        "type" : "orderBookRemove"
    },
    "results" : [ 
        {
            "k" : "bid",
            "v" : {
                "count" : 15.0
            }
        }, 
        {
            "k" : "ask",
            "v" : {
                "count" : 3.0
            }
        }
    ]
},
{
    "_id" : {
        "_id" : 1498276800.0,
        "type" : "orderBookModify"
    },
    "results" : [ 
        {
            "k" : "bid",
            "v" : {
                "count" : 16.0
            }
        }, 
        {
            "k" : "ask",
            "v" : {
                "count" : 1.0
            }
        }
    ]
}

Когда применяется последняя часть трубопровода, т.е.

{ "$group": {
    "_id": "$_id._id",
    "results": {
      "$push": {
        "k": "$_id.type",
        "v": "$results"
      }
    }
  }}

Я получаю это, только первый элемент "bid" из массива результатов. Второй вопрос "спросить" идет AWOL?

{
    "_id" : 1498280700.0,
    "results" : [ 
        {
            "k" : "orderBookRemove",
            "v" : [ 
                {
                    "k" : "bid",
                    "v" : {
                        "count" : 9.0
                    }
                }
            ]
        }, 
        {
            "k" : "orderBookModify",
            "v" : [ 
                {
                    "k" : "bid",
                    "v" : {
                        "count" : 6.0
                    }
                }
            ]
        }
    ]
}
Теги:
aggregation-framework

1 ответ

1
Лучший ответ

Это полностью зависит от версии MongoDB, доступной вам или нет, в зависимости от того, как вы ее смотрите. Как вы говорите, данные на самом деле из массива изначально, поэтому я собираюсь начать в этом формате и обрабатывать каждый вариант оттуда.

Источником считается тогда:

{
        "_id" : ObjectId("594f3a530320738061df3eea"),
        "data" : [
                {
                        "_id" : 1498290900,
                        "trade" : {
                                "type" : "Modify",
                                "data" : {
                                        "type" : "bid",
                                        "rate" : "0.00658714",
                                        "amount" : "3.82354427"
                                },
                                "date" : 1498290930291,
                                "name" : "TLX"
                        }
                },
                {
                        "_id" : 1498290900,
                        "trade" : {
                                "type" : "Modify",
                                "data" : {
                                        "type" : "ask",
                                        "rate" : "0.00658714",
                                        "amount" : "3.82354427"
                                },
                                "date" : 1498290930291,
                                "name" : "TLX"
                        }
                },
                {
                        "_id" : 1498290900,
                        "trade" : {
                                "type" : "Remove",
                                "data" : {
                                        "type" : "ask",
                                        "rate" : "0.00680891"
                                },
                                "date" : 1498290931349,
                                "name" : "TLX"
                        }
                }
        ]
}

MongoDB 3.4

Просто используйте $replaceRoot и $arrayToObject с некоторым тщательным размещением результатов:

db.dtest.aggregate([
  { "$unwind": "$data" },
  { "$group": { 
   "_id": {
     "_id": "$data._id", 
     "type": "$data.trade.type",
     "dtype": "$data.trade.data.type"
   },
   "count": { "$sum": 1 }
  }},
  { "$group": {
    "_id": {
      "_id": "$_id._id",
      "type": "$_id.type"
    },
    "results": {
      "$push": {
        "k": "$_id.dtype",
        "v": {
          "count": "$count"
        }
      }         
    }
  }},
  { "$group": {
    "_id": "$_id._id",
    "results": {
      "$push": {
        "k": "$_id.type",
        "v": "$results"
      }
    }
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": {
        "$concatArrays": [
          [{ "k": "_id", "v": "$_id" }],
          { "$map": {
            "input": "$results",
            "as": "r",
            "in": {
              "k": "$$r.k",
              "v": { "$arrayToObject": "$$r.v" }
            }
          }}
        ]
      }
    }
  }}
])

Все версии

Это то, что, вероятно, имеет наибольший смысл в большинстве случаев, когда мы просто делаем агрегированную форму массива и вместо этого делаем преобразование в клиенте. Нам не нужна дополнительная агрегация, поскольку эта часть уже выполнена, поэтому нам не нравится, что мы уменьшаем данные.

Простота работы на большинстве языков, но в качестве базовой концепции JavaScript, которая работает в оболочке:

db.dtest.aggregate([
  { "$unwind": "$data" },
  { "$group": { 
   "_id": {
     "_id": "$data._id", 
     "type": "$data.trade.type",
     "dtype": "$data.trade.data.type"
   },
   "count": { "$sum": 1 }
  }},
  { "$group": {
    "_id": {
      "_id": "$_id._id",
      "type": "$_id.type"
    },
    "results": {
      "$push": {
        "k": "$_id.dtype",
        "v": {
          "count": "$count"
        }
      }         
    }
  }},
  { "$group": {
    "_id": "$_id._id",
    "results": {
      "$push": {
        "k": "$_id.type",
        "v": "$results"
      }
    }
  }}
]).map(doc => 
  doc.results.map(r => 
    ({ k: r.k, v: r.v.reduce((acc,curr) =>
      Object.assign(acc, { [curr.k]: curr.v }),{}) 
    })
  ).reduce((acc,curr) => 
    Object.assign(acc, { [curr.k]: curr.v }),{ _id: doc._id })
)

Что по сути делает то же самое, что и обработка курсора, поскольку новый сценарий "причудливого конвейера" выполняется для каждого документа.

Поэтому действительно стоит показать, что, если вы не собираетесь собирать результаты дальше, чем от этого результата, просто нет необходимости использовать новые фантастические операторы. То же самое достигается тем, что значительно меньше строк кода и гораздо менее кратким для выражения.

Оба выводят одно и то же:

    {
            "_id" : 1498290900,
            "Modify" : {
                    "ask" : {
                            "count" : 1
                    },
                    "bid" : {
                            "count" : 1
                    }
            },
            "Remove" : {
                    "ask" : {
                            "count" : 1
                    }
            }
    }

Отладка - удаление

Принимая данные из вашего обновления, я применяю это:

db.test.aggregate([
  { "$group": {
    "_id": "$_id._id",
    "results": {
      "$push": {
        "k": "$_id.type",
        "v": "$results"
      }
    }
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": {
        "$concatArrays": [
          [{ "k": "_id", "v": "$_id" }],
          { "$map": {
            "input": "$results",
            "as": "r",
            "in": {
              "k": "$$r.k",
              "v": { "$arrayToObject": "$$r.v" }
            }
          }}
        ]
      }
    }
  }}
 ])

И получить ожидаемый результат:

{
    "_id" : 1498276800.0,
    "orderBookRemove" : {
        "bid" : {
            "count" : 15.0
        },
        "ask" : {
            "count" : 3.0
        }
    },
    "orderBookModify" : {
        "bid" : {
            "count" : 16.0
        },
        "ask" : {
            "count" : 1.0
        }
    }
}

Таким образом, ваш заявленный результат является ложным, и вы не следуете примеру.

  • 0
    спасибо .. я использую 3.4. Я попробовал вариант 2, но он работал до последней стадии конвейера, но переносит только один элемент массива результатов. Я обновил вопрос в разделе UPDATE с примером того, что я вижу.
  • 0
    @FloWoo Вы не взяли «весь» конвейер в ответе. Вы пропускаете этап с $replaceRoot который является последним этапом, или альтернативный подход кода, обрабатывающий результат курсора. Конечно, это работает, потому что, как я ясно выразился, я использую ваши собственные данные в вопросе и показываю вывод, который совпадает с тем, что вы просили. Добавьте на последнем этапе и запустите снова.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню