Как написать запрос mongodb, когда все ключи разные - PullRequest
1 голос
/ 17 января 2020

У меня есть коллекция mongodb, в которой есть куча документов. Каждый документ будет иметь следующий формат

{ 
    "_id" : "xyz", 
    "t_1" : {
        "start" : "2018-07-18 04:12:00+00:00", 
        "duration" : "0 days 00:06:28", 
        "A": 10
     },
    "t_2" : {
        "start" : "2018-07-24 07:15:00+00:00", 
        "duration" : "0 days 00:06:28", 
        "B": 20
     },
...
}

Как мне написать запрос, чтобы найти

  1. t s (t_1, t_2 et c .) для данного _id, у которого B больше 10
  2. начала поиска t с, у которого B больше 10 для данного _id
  3. поиска _id документов, которые имеют по крайней мере один B в t s

Обратите внимание, что не обязательно, чтобы все t имели ключ B. Некоторые из них не могут

1 Ответ

1 голос
/ 17 января 2020

Один из способов обойти это - запустить агрегатный конвейер, который получает данные о ключах на уровне root документа, обозначенного системной переменной $$ROOT, через их значения и определите, есть ли у них более одного ключа.

Для первого шага введите $addFields, добавьте дополнительное поле, содержащее вышеприведенные вычисления, и используйте $objectToArray* 1011. * для преобразования пар ключ / значение в массив [ { k: 'key name': v: 'value' }, ... ]

db.collection.aggregate([
    { '$addFields': {
        'fields': { '$objectToArray': '$$ROOT' }
    } }
])

При получении этого массива следующим шагом будет фильтрация списка

db.collection.aggregate([
    # convert dynamic fields to key/value arrays
    { '$addFields': {
        'fields': { '$objectToArray': '$$ROOT' }
    } },

    # filter where B > 10
    { '$addFields': {
        'fields': {
            '$filter': {
                'input': '$fields',
                'cond': {
                    '$and': [
                        { '$ne':  [ { '$type' : "$$this.v.B" }, 'missing'] },
                        { '$gt': [ "$$this.v.B", 10 ] }
                    ]
                }
            }
        }
    } }
])

Конвейеры для затем следуют требуемые запросы:

1. t s (t_1, t_2 et c.) для данного _id, который имеет B больше 10

db.collection.aggregate([
    { '$addFields': {
        'fields': {
            '$filter': {
                'input': { '$objectToArray': '$$ROOT' },
                'cond': {
                    '$and': [
                        { '$ne':  [ { '$type' : "$$this.v.B" }, 'missing'] },
                        { '$gt': [ "$$this.v.B", 10 ] }
                    ]
                }
            }
        }
    } },
    { '$addFields': {
        't_s': '$fields.k' 
    } }
])

2. найти начало t с, у которых B больше 10 для данного _id

db.collection.aggregate([
    { '$match': { '_id': "xyz" } },
    { '$addFields': {
        'fields': {
            '$filter': {
                'input': '$fields',
                'cond': {
                    '$and': [
                        { '$ne':  [ { '$type' : "$$this.v.B" }, 'missing'] },
                        { '$gt': [ "$$this.v.B", 10 ] }
                    ]
                }
            }
        }
    } },
    { '$addFields': {
        'start_times': '$fields.v.start' 
    } }
])

3. найти _id документов, в которых есть хотя бы один B ТС

db.collection.aggregate([
    # convert root dynamic fields to key/value pair array
    { '$addFields': {
        'fields': { '$objectToArray': '$$ROOT' }
    } },


    # filter all documents where size of array of Bs >= 1
    { '$match': {
        '$expr': {
            '$gte': [
                { '$size': '$fields.v.B' },
                1
            ]
        }
    } },


    # get array of _ids
    { '$addFields': {
        'ids': {
            '$filter': {
                'input': '$fields',
                'cond': { '$eq': [ '$$this.k', '_id' ] }
            }
        }
    } },

    # reshape field
    { '$addFields': {
        'ids': '$ids.v'
    } }
])
...