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-кода, но она по-прежнему доступна на текущей стабильной версии.