Ответы пользователя по тегу MongoDB
  • Как выставить параметр по умолчанию?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    В данный момент такая возможность отсутствует, но в джире MongoDB несколько лет назад было небольшое обсуждение о такой возможности.
    Пока такая возможность не появится, лучшее, что можно сделать - проставлять значение по умолчанию в коде, который создаёт/сохраняет новый документ в БД.
    Ответ написан
    Комментировать
  • Как сделать запрос к mongodb для фильтрации по типу поля?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    В данном случае надо использовать оператор $not для отрицания равенства. Пример данных:
    db.test.insertMany([
      {
        "field1": "abc",
        "field2": [
          {"embeddedField": "a"},
          {"embeddedField": "b"},
          {"embeddedField": "c"}
        ]
      },
      {
        "field1": "xyz",
        "field2": {
          "embeddedField1": "x",
          "embeddedField2": "y",
          "embeddedField3": "z"
        }
      }
    ])


    Запрос:
    db.test.find({"field2": {$not: {$type: "array"}}})

    Результат:
    {
      "_id": ObjectId("..."),
      "field1": "xyz",
      "field2": {
        "embeddedField1": "a",
        "embeddedField2": "b",
        "embeddedField3": "c"
      }
    }
    Ответ написан
    Комментировать
  • Как получить часть документа mongodb?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Для этой задачи вам надо использовать проекцию. Их в монге несколько видов:

    1. Используется в запросах find, findOne, findOneAndDelete, findOneAndReplace и findOneAndUpdate
    2. Используется для фильтрации элементов массива
    3. Используется как отдельная стадия аггрегации


    1 тип аггрегации позволяет только скрыть лишние элементы из ответа. Если воспользоваться этим типом, то запрос будет выглядеть вот так:
    db.subjects.find(
    	{"ФизМат.Педагогические науки.B009": {$exists: true}}, // Из всех документов (если у вас их несколько, а не один огромный документ), выбрать те, у которых существует поле "ФизМат.Педагогические науки.B009"
    	{
    		_id: 1, // У найденного документа вернуть только поле _id
    		"ФизМат.Педагогические науки.B009": 1 // и поле "ФизМат.Педагогические науки.B009"
    	}
    )


    Ответ на такой запрос:
    {
      "_id": ObjectId("600fa6f3101fa920a8575e6f"),
      "ФизМат": {
        "Педагогические науки": {
          "B009": {
            "code": "B009",
            "name": "Подготовка учителей математики",
            "max": "140",
            "min": " 107",
            "minWithQuota": " 95"
          }
        }
      }
    }


    т.е. будут скрыты все поля, кроме _id и ФизМат.Педагогические науки.B009, никаких дополнительных преобразований над документом проводиться не будет.

    2 тип используется что бы из массива выбрать только первое подходящее значение, но у вас предметы оформлены не в виде массива документов, поэтому этот тип пропустим.

    3 тип - как стадия аггрегации. Аггрегация в монге - довольно мощный инструмент, который позволяет группировать результаты, преобразовывать их, делать многоуровневый поиск и т.п.
    В данном случае сам запрос будет выглядеть совершенно по другому:
    db.subjects.aggregate(
    [
      { 
        $match: { // Эта стадия ищет документы, подходящие под условие
          "ФизМат.Педагогические науки.B009": {$exists: true} // В документе есть поле "ФизМат.Педагогические науки.B009"
        } 
      },
      { 
        $project: { // Стадия проекции
          _id: 1, // Вернуть id документа
          value: "$ФизМат.Педагогические науки.B009" // Вернуть embedded документ в поле value
        }
      },
    ])


    Ответ в таком случае будет выглядеть вот так:
    {
      "_id": ObjectId("600fa6f3101fa920a8575e6f"),
      "value": {
        "code": "B009",
        "name": "Подготовка учителей математики",
        "max": "140",
        "min": " 107",
        "minWithQuota": " 95"
      }
    }
    Ответ написан
    1 комментарий
  • Как указать несколько пар условий в запросе по списку?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Про хешированные индексы
    Судя по документации, MongoDB не поддерживает хешированные индексы для массивов.
    Хешированные индексы нужны для того, что бы более равномерно распределить данные, которые расположены близко к друг другу. Их часто применяют при шардировании коллекций (когда одна коллекция разбита на несколько частей, которые хранятся на разных серверах). В таком случае, запросы на выбор этих данных не будут идти всегда на один и тот же сервер. Но если у вас запросы вида поле1 > значение1 && поле1 < значение2, то индекс использоваться не будет (потому что в таком случае монге надо будет сгенерировать все возможные промежуточные значения и посчитать для них хеши, что невозможно).

    Но судя по документации, хешированные индексы также можно применять и для embedded-документов (сам так не делал), но подозреваю, что в таком случае в запросе надо передавать весь embedded-документ, что бы для него правильно посчитался хеш.

    Про индексы в целом
    В целом, задача индекса в том, что бы после первичного поиска по нему осталось как можно меньше документов для последующего перебора, поэтому рекомендуется строить индекс по полям, которые у вас гарантированно участвуют в каждом запросе.
    Скажем, у вас в коллекции проиндексированно только поле username и вы выполняете свой запрос вида
    $or: [
    ["username" : "user1", tags: "tag4"],
    ["username" : "user2", tags: "tag1"],
    ["username" : "user2", tags: "tag3"],
    ]

    в таком случае, MongoDB с помощью индекса очень быстро выберет все документы, у которых username равен либо user1, либо user2, а затем уже начнёт перебирать найденные документы и проверять их на совпадение остальным параметрам запроса.

    Получается, лучше делать составной индекс username + tags?
    Не всегда. При использовании в индексе поля типа Array, на каждый элемент массива будет создана отдельная запись в индексе.
    Если у вас мало документов, у которых поле username имеет одинаковое значение, но при этом в массиве tags может быть много значений, и значения внутри одного массива могут повторяться, то использование составного индекса приведёт к большему количеству одинаковых записей в индексе, чем если бы вы использовали индексацию только по полю username.

    Отсюда же вытекает другое ограничение: в составном индексе только одно из полей может быть массивом, иначе в индексе на каждый документ пришлось бы создавать N ・ M записей, где N и M - размеры массивов, которые участвуют в построении индекса.

    Отдельное поле с хешем
    В таком случае, вам при каждом редактировании документа надо будет загружать полный документ из базы, обновлять его, вычислять вручную новый хеш и сохранять документ обратно. А значит вы не сможете использовать запросы, которые обновляют только отдельные поля, например прямое редактирование массива.

    Отдельная коллекция с хешами
    Транзакционность в MongoDB есть только на уровне отдельного документа. А это значит, что вам придётся самому следить за консистентностью данных в обеих коллекциях, что может обернуться той ещё головной болью: что вы будете делать, если документ был отредактирован, но информация в связанной коллекции по каким-то причинам не была обновлена (например, прервалась связь с БД или приложение упало из-за нехватки памяти)? Поэтому лично я в общем случае такой подход не рекомендовал бы.

    Так что же делать?
    Самое простое и эффективное, что вы можете сделать - поднять монгу локально, сгенерировать в ней реалистичные данные, поиграться с разными настройками индексов и замерить скорость выполнения запросов.
    Дополнительно можете воспользоваться методом explain, что бы посмотреть статистику выполнения запроса.
    Ответ написан
    Комментировать
  • Как работает поиск в массиве mongoDB через Spring Data?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Ответ зависит от того, какой именно запрос сгенерирует Spring Data для метода countByActiveStatesIn(Set states);.

    Судя по таблице №16 раздела 15.3 документации Spring Data MongoDB, должен сгенерироваться запрос
    db.collectionName.count({ activeStates: { $in: ["logicConnectionLost"] }})

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

    Какой именно запрос был сгенерирован, можно проверить выставив уровень логирования в DEBUG:
    logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG
    
    #Если используете реактивный MongoTemplate:
    logging.level.org.springframework.data.mongodb.core.ReactiveMongoTemplate=DEBUG
    Ответ написан
    Комментировать