MongoDB - головоломка запроса - Документ refs или поддокумент

У меня возникла проблема с некоторыми данными, которые я храню в моем MongoDB (Примечание: я использую mongoose в качестве ODM). У меня две схемы:

mongoose.model('Buyer',{
  credit: Number,
})

и

mongoose.model('Item',{
  bid: Number,
  location: { type: [Number], index: '2d' }
})

Покупатель/элемент будет иметь родительскую/дочернюю связь с отношением "один ко многим". Я знаю, что я могу настроить элементы для встраивания поддоков в документ покупателя или. Я могу создать два отдельных документа с ссылками на объекты id друг на друга.

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

Чтобы удовлетворять первым критериям, кажется, что я должен вставлять элементы в качестве поддомена, чтобы я мог сравнивать два числа. Но, чтобы сравнить места с запросом geoNear, кажется, было бы лучше отделить документы, иначе я не смогу выполнить geoNear для каждого вложенного документа.

Есть ли способ, которым я могу выполнять обе задачи по этим данным? Если да, то каким образом я должен структурировать свои данные? Если нет, существует ли способ, которым я могу выполнить один запрос, а затем второй запрос результата из первого запроса?

Спасибо за вашу помощь!

Ответ 1

Существует еще один вариант (помимо внедрения и нормализации) для хранения иерархий в mongodb, который хранит их как древовидные структуры. В этом случае вы будете хранить Покупателей и Элементы в отдельных документах, но в той же коллекции. Каждому элементу документа потребуется поле, указывающее на его документ покупателя (родителя), и каждое родительское поле документа покупателя будет установлено равным нулю. Документы, которые я связал, чтобы объяснить несколько реализаций, которые вы могли бы выбрать.

Ответ 2

Если ваши объекты хранятся в двух отдельных коллекциях, чем лучший вариант, вы будете писать свою собственную функцию и называть ее с помощью mongoose.connection.db.eval('some code...');. В таком случае вы можете выполнить свою расширенную логику на стороне сервера.

Вы можете написать примерно следующее:

var allNearItems = db.Items.find(
    { location: {
        $near: {
            $geometry: {
              type: "Point" ,
              coordinates: [ <longitude> , <latitude> ]
            },
            $maxDistance: 100
        }
    }
}); 
var res = [];
allNearItems.forEach(function(item){
    var buyer = db.Buyers.find({ id: item.buyerId })[0];
    if (!buyer) continue;
    if (item.bid < buyer.credit) {
        res.push(item.id);
    }
});
return res;

После оценки (поместите его в вызов mongoose.connection.db.eval("...")) вы получите массив идентификаторов элементов.

Используйте его с предостережениями. Если ваш массив allNearItems будет слишком большим или вы будете часто его запрашивать, вы можете столкнуться с проблемами производительности. Команда MongoDB фактически отказалась от выполнения прямого js-кода, но она по-прежнему доступна на текущей стабильной версии.