Как написать следующий запрос MongoDB - PullRequest
0 голосов
/ 28 августа 2018

Предположим, у меня есть следующая foobar коллекция:

{
  "foobar": [
    {
      "_id": "abc",
      "history": [
        {
          "type": "foo",
          "timestamp": 123456789.0
        },
        {
          "type": "bar",
          "timestamp": 123456789.0
        }
      ]
    },
    {
      "_id": "dfg",
      "history": [
        {
          "type": "baz",
          "timestamp": 123456789.0
        },
        {
          "type": "bar",
          "timestamp": 123456789.0
        }
      ]
    },
    {
      "_id": "hij",
      "history": [
        {
          "type": "foo",
          "timestamp": 123456789.0
        },
        {
          "type": "bar",
          "timestamp": 123456789.0
        },
        {
          "type": "foo",
          "timestamp": 123456789.0
        }
      ]
    }
  ]
}

Как я могу запросить ($gte / $lte) элементы foobar, основанные на подпорке timestamp внутри их history элементов, но используя timestamp от элемента, где type: "foo"?

Если нет вложенных документов с type, равным foo, весь документ отфильтровывается, если имеется более одного вложенного документа с type, равным foo, тогда он может соответствовать любому.

1 Ответ

0 голосов
/ 29 августа 2018

Вы можете попробовать ниже агрегации:

var threshold = 123456788;
db.foobar.aggregate([
    {
        $addFields: {
            foobar: {
                $filter: {
                    input: "$foobar",
                    as: "doc",
                    cond: {
                        $let: {
                            vars: { 
                                foo: {
                                    $arrayElemAt: [
                                        {
                                            $filter: {
                                                input: "$$doc.history",
                                                as: "history",
                                                cond: {
                                                    $eq: [ "$$history.type", "foo" ]
                                                }
                                            }
                                        },
                                        0]
                                }
                            },
                            in: {
                                $gt: [ "$$foo.timestamp", threshold ]
                            }
                        }
                    }
                }
            }
        }
    }
])

$ addFields может использоваться для перезаписи существующего поля (foobar). Чтобы отфильтровать все вложенные документы, не соответствующие вашему условию, вы можете использовать $ filter (внешний). Для каждого foobar документа вы можете использовать $ let для определения временной переменной foo. Вам нужен внутренний $filter, чтобы получить все history элементы, где type равен foo, а затем $ arrayElemAt , чтобы получить первый. Тогда вам просто нужно $gt или $lt, чтобы применить ваше сравнение.

Для тех поддокументов, где нет foo, будет возвращено undefined, которое затем будет отфильтровано на этапе $gt.

...