Найти максимальную длину данных в ключах для коллекции

1
{
  "_id" : ObjectId("59786a62a96166007d7e364dsadasfafsdfsdgdfgfd"),
  "someotherdata" : {
    "place1" : "lwekjfrhweriufesdfwergfwr",
    "place2" : "sgfertgryrctshyctrhysdthc ",
    "place3" : "sdfsdgfrdgfvk",
    "place4" : "asdfkjaseeeeeeeeeeeeeeeeefjnhwklegvds."
  }
}

У меня есть тысячи из них в моей коллекции. Мне нужно просмотреть все someotherdata и сделать следующее

  1. Проверьте, присутствует ли он (в некоторых записях у меня есть place1, а не place4)
  2. Найдите самую длинную запись (в терминах длины строки)

Результат должен выглядеть примерно так (показывая количество символов для самого длинного)

{   
  place1: 123,
  place2: 12,
  place3: 17
  place4: 445
}

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

EDIT: Чтобы быть ясным, я хочу, чтобы самый длинный во всей коллекции. Таким образом, может быть 1000 документов, но только один результат с самой длинной длиной для каждого поля всей коллекции.

  • 0
    Без доступа к $strLenBytes или $strLenCP вам потребуется использовать mapReduce и возвращать длину каждого свойства с помощью функций JavaScript. Не совсем понятно, запрашиваете ли вы «самую длинную длину каждого ключа» во всей коллекции, или «просто длину каждого ключа в документе», или даже действительно, каким должен быть результат. Например, вы показываете документ с 4 возможными ключами и выводите только для 3.
  • 0
    @NeilLunn Я отредактировал свой ответ
Теги:
mapreduce

2 ответа

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

Используйте .mapReduce() чтобы уменьшить до самых больших значений для каждого ключа:

db.collection.mapReduce(
  function() {
    emit(null,
      Object.keys(this.someotherdata).map(k => ({ [k]: this.someotherdata[k].length }))
       .reduce((acc,curr) => Object.assign(acc,curr),{})
    );
  },
  function(key,values) {
    var result = {};
    values.forEach(value => {
      Object.keys(value).forEach(k => {
        if (!result.hasOwnProperty(k))
          result[k] = 0;
        if ( value[k] > result[k] )
          result[k] = value[k];
      });
    });
    return result;
  },
  { 
    "out": { "inline": 1 },
    "query": { "someotherdata": { "$exists": true } }
  }
)

Что в основном испускает "length" каждой клавиши, присутствующей в пути субдокумента для каждого документа, а затем в "сокращении" фактически возвращается только самая большая "length" для каждой клавиши.

Обратите внимание, что в mapReduce вам нужно поместить ту же структуру, в которую вы вложили, поскольку способ, которым он имеет дело с большим количеством документов, - это "сокращение" в поэтапных партиях. Вот почему мы emit цифровую форму, как и функция "reduce".

Дает этот результат в вашем документе, указанном в вопросе. Конечно, это "макс" по всем документам в коллекции, когда у вас их больше.

   {
        "_id" : null,
        "value" : {
            "place1" : 25.0,
            "place2" : 26.0,
            "place3" : 13.0,
            "place4" : 38.0
        }
    }

Для заинтересованного, контекст вопроса состоит в том, что функции MongoDB 3.4 были недоступны для них. Но делать то же самое, используя .aggregate() где доступны функции:

db.collection.aggregate([
  { "$match": { "someotherdata": { "$exists": true } } },
  { "$project": {
    "_id": 0,
    "someotherdata": {
      "$map": { 
        "input": { "$objectToArray": "$someotherdata" },
        "as": "s",
        "in": { "k": "$$s.k", "v": { "$strLenCP": "$$s.v" } }
      }
    }
  }},
  { "$unwind": "$someotherdata" },
  { "$group": {
     "_id": "$someotherdata.k",
     "v": { "$max": "$someotherdata.v" }    
  }},
  { "$sort": { "_id": 1 } },
  { "$group": {
    "_id": null,
    "data": {
      "$push": { "k": "$_id", "v": "$v" }
    }    
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"   
    } 
  }}
])

С тем же выходом:

{
    "place1" : 25,
    "place2" : 26,
    "place3" : 13,
    "place4" : 38
}
  • 0
    Когда я запускаю оболочку ROBO 3T mongo, она говорит: «Ошибка: строка 6: неожиданный токен;»
  • 0
    @ 32423hjh32423 Мой плохой. Отсутствие скобок.
Показать ещё 5 комментариев
0

Используйте cursor.forEach для итерации по коллекции. Следите за самыми длинными значениями площади (начиная с -1, обновляя, когда больше найдено). Распечатывать значения с помощью print() или printjson()

Ещё вопросы

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