MongoDB лучшая практика для сортировки по неиндексированным полям - PullRequest
1 голос
/ 04 июня 2019

У меня есть приложение, которое позволяет пользователям использовать свои собственные пользовательские данные, поэтому я не могу знать, что это за данные. Тем не менее, я хочу разрешить им сортировать данные. Это может быть значительный объем данных, и mongodb выдает мне ошибки памяти (ограничение 32 МБ)

Как лучше всего подойти к этому? Как я могу позволить пользователю сортировать большой объем данных по неизвестному полю?

Ответы [ 3 ]

1 голос
/ 04 июня 2019

Поскольку вы пометили этот вопрос Meteor, я полагаю, у вас есть среда Meteor по умолчанию, в которой вы можете использовать легкие коллекции Mongo на стороне клиента .

Это дает вам возможностьПубликация (публикация) / возврат (метод) ваших данных в основном не отсортированы, и пусть клиент справится с этой задачей.

Подумайте так: всего 100 клиентов запрашивают публикацию, которая обновляется при каждом действии сортировки (поскольку параметры подписки изменяются,поэтому публикация тоже меняется).

Это приводит к тому, что ваш сервер уже использует большой объем ОЗУ, чтобы наблюдатели (OPLOG и т. д.) работали для 100 публикаций, каждая из которых запрашивает огромное количество документов.

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

Вариант A - Публикация несортированных, пусть клиенты сортируют

сервер

Meteor.publish('hugeData', function () {
  return MyCollection.find({ ...})
})

client

const handle = Meteor.subscribe('hugeData')
if (handle.ready()) {
  const sortedData = MyCollection.find({ ... }, {sort: { someField: -1 } })
}

Большой плюс в том, что вы можете информировать клиентов о статусе полноты, если используете cursor.observeChanges.

Обратите внимание, что если вы хотите сканировать в обратном направлении (возвратите документы, с самыми новыми), вы можете использовать опцию hint при поиске :

Meteor.publish('hugeData', function () {
  return MyCollection.find({ ...}, { hint: { $natural : -1 })
})

Это гораздо большес производительностью, превышающей { sort: { fieldName: -1} }.

Опция B - вернуть несортированный из метода, разрешить клиентам сортировать

Теперь все еще может быть проблема с решением A, так как он все еще имеет много оперативной памяти для потребленияесли есть много подписчиков.Альтернатива (особенно если изменения данных в реальном времени не так важны) заключается в использовании метеорных методов:

сервер

Meteor.method('hugeData', function () {
  return MyCollection.find({ ...}).fetch()
})

Обратите внимание, что для этого требуется fetch документы, в противном случае и unhandledPromiseRejection выбрасывается.

клиент

Для этого требуется LocalCollection на клиенте, то есть не синхронизирован с вашей коллекцией на стороне сервера, или у вас возникнут проблемы с синхронизацией документов:

const HugeData = new LocalCollection(null) // note the null as collection name!

const insertUpdate = document => {
  if (LocalCollection.findOne(document._id)) {
    delete document._id
    return LocalCollection.update(document._id, document)
  } else {
    return LocalCollection.insert(document)
  }
}

Meteor.call('hudeData', (err, data) => {
  data.forEach(insertUpdate)
})

Затем вы можете использовать LocalCollection на клиенте для любой проекции полученных данных.

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

1 голос
/ 04 июня 2019

MongoDB позволяет вам спроектировать схему таким образом, чтобы она могла хранить объекты и отношения объектов в схеме, так что вы можете позволить пользователю хранить любую информацию. Как сказал @kevinadi, ограничение составляет 32 МБ. Что касается сортировки, то это можно сделать на вашем сервере.

Это пример, который я пробовал при хранении объектов в MongoDB и Mongoose ORM

var mongoose = require("mongoose");
var userSchema = new mongoose.Schema({
  email: {
    type: String,
    unique: true,
    required: true,
    lowercase: true,
    trim: true,
    match: [/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, "Please fill a valid email address"]
  },
  custInfo:{
  type:Object,
  required: true
  }
  isConfirmed: {
    type: Boolean,
    required: true,
    default: false
  },
  confirmedOn:{
    type: Date,
    required: true,
    default: Date.now()
  }
});

module.exports = mongoose.model("user",userSchema);
0 голосов
/ 07 июня 2019

Моя текущая мысль - это дополнительная индексированная коллекция, содержащая 1.entity id, имя 2 полей 3. значение поля.Индексируйте эту коллекцию, а затем извлекайте оттуда упорядоченные идентификаторы сущностей, а затем загружайте полные соответствующие документы по идентификатору.

...