Почему MongoDB не поддерживает запросы свойств встроенных документов, которые хранятся в хеш-массивах?
Почему MongoDB не поддерживает запросы свойств встроенных документов, которые хранятся с использованием хешей?
Например, скажем, у вас есть коллекция под названием "счета-фактуры", которая была создана следующим образом:
db.invoices.insert(
[
{
productsBySku: {
12432: {
price: 49.99,
qty_in_stock: 4
},
54352: {
price: 29.99,
qty_in_stock: 5
}
}
},
{
productsBySku: {
42432: {
price: 69.99,
qty_in_stock: 0
},
53352: {
price: 19.99,
qty_in_stock: 5
}
}
}
]
);
При такой структуре запросы MongoDB с $elemMatch, точечным синтаксисом или позиционным оператором ($) не могут получить доступ ни к одному из свойств каждого члена productsBySku.
Например, вы не можете сделать что-либо из этого:
db.invoices.find({"productsBySku.qty_in_stock":0});
db.invoices.find({"productsBySku.$.qty_in_stock":0});
db.invoices.find({"productsBySku.qty_in_stock":{$elemMatch:{$eq:0}}});
db.invoices.find({"productsBySku.$.qty_in_stock":{$elemMatch:{$eq:0}}});
Поэтому, чтобы найти товары, которых нет в наличии, вы должны использовать запрос $ where, например:
db.invoices.find({
$where: function () {
for (var i in this.productsBySku)
if (!this.productsBySku[i].qty_in_stock)
return this;
}
});
На техническом уровне... почему они разработали MongoDB с таким жестким ограничением на запросы? Конечно, должна быть какая-то техническая причина для этого кажущегося серьезного недостатка. Является ли эта неспособность работать со списком объектов в виде массива, игнорируя ключи, просто ограничение JavaScript как языка? Или это было результатом какого-то архитектурного решения в MongoDB?
Просто любопытно.
2 ответа
Если я честен, я не уверен, вы должны спросить у MongoDB Inc. (10gen) сами. Я попытаюсь объяснить некоторые из моих рассуждений.
Я немного искал в Google и, похоже, ничего не появляется: https://www.google.co.uk/search?q=mognodb+jira+support+querying+objects&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla: ан-ГБ: официальный и клиент = светлячок-а & канал = fflb & gfe_rd = CR & е =as9pVOW3OMyq8wfhtYCgCw# RLS = org.mozilla: ан-ГБ: официальный канал = & fflb & д = MongoDB + JIRA + + запрашивающие объекты
Быстро можно увидеть, как использование объектных свойств для ключей может быть выгодным, например: запросы на удаление не должны были бы искать каждый объект и его свойства в массиве, а вместо этого просто находили единственное свойство объекта в родительском объекте и сбрасывали его. По сути это будет разница:
[
{id:1, d:3, e:54},
{id:3, t:6, b:56}
]
а также:
{
1: [d:3, e: 54],
3: [t:6, b:56]
}
с последним, очевидно, гораздо быстрее удалить идентификатор 3
,
Не только это, но и все операции с массивами, которые вводит MongoDB, из $elemMatch
в $unwind
будет работать с объектами, я имею в виду, как раскручивать:
[
{id:5, d:4}
]
сильно отличается от раскручивания:
{
5: {d:4}
}
?
Поэтому, если честно, я не могу ответить на ваш вопрос. У Google нет защиты в отношении их решения, и нет никаких подробных рассуждений о том, что я могу найти.
На самом деле я зашел так далеко, что нашел несколько раз, в том числе: https://www.google.co.uk/search?q=array+operations+that+do+not+work+on+objects&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-GB:official&client=firefox-a&channel=fflb&gfe_rd=cr&ei=DtNpVLrwDsPo7AaH4oCoDw и я нашел результаты, которые зашли так далеко underscore.js
которые фактически выполняют свои функции массива для всех объектов.
Единственная реальная причина, о которой я могу думать, это стандартизация. Вместо того, чтобы обслуживать все группы меньшинств и т. Д. О том, как могут работать поддокументы, они просто обслуживают одно меньшинство, ставшее большинством по своему выбору.
Это один из моментов, связанных с MongoDB, который смущает меня даже сейчас, поскольку в моем собственном программировании много раз, когда кажется, что для скорости и мощности выгодно использовать объекты вместо массивов.
Практическое правило. Обычно это не технические проблемы, а проблемы с моделированием данных. Я еще не нашел вариант использования, в котором имеет смысл иметь ключи, содержащие семантическое значение.
Если бы у вас было что-то вроде
'products':[
{sku:12432,price:49.99,qty_in_stock:4},
{sku:54352,price:29.99,qty_in_stock:5}
]
Было бы намного больше смысла.
Но: вы моделируете счета. Счет должен - по многим причинам - отражать статус в определенный момент времени. Постоянно меняющийся запас редко относится к счету. Итак, вот как я бы смоделировал данные для товаров и счетов
{
'_id':'12432',
'name':'SuperFoo',
'description':'Without SuperFoo, you can't bar or baz!',
'current_price':49.99
}
То же самое с другими предметами.
Теперь счет будет выглядеть довольно просто:
{ _id:"Invoice2",
customerId:"987654"
date:ISODate("2014-07-07T12:42:00Z"),
delivery_address:"Foo Blvd 42, Appt 42, 424242 Bar, BAZ"
items:
[{id:'12432', qty: 2, price: 49.99},
{id:'54352', qty: 1, price: 29.99}
]
}
Теперь в счете будут храниться вещи, которые могут быть действительными только в определенный момент времени (цены и адрес доставки могут измениться), и ваш запас и счета будут запрошены легко:
// How many items of 12432 are in stock?
db.products.find({_id:'12432'},{qty_in_stock:1})
// How many items of 12432 were sold during July and what was the average price?
db.invoices.aggregate([
{$unwind:"$items"},
{
$match:{
"items.id":"12432",
"date":{
$gt:ISODate("2014-07-01T00:00:00Z"),
$lt:ISODate("2014-08-01T00:00:00Z")
}
}
},
{$group : { _id:"$items.id", count: { $sum:"$items.qty" }, avg:{$avg:"$items.price"} } }
])
// How many items of each product sold did I sell yesterday?
db.invoices.aggregate([
{$match:{ date:{$gte:ISODate("2014-11-16T00:00:00Z"),$lt:ISODate("2014-11-17T00:00:00Z")}}},
{$unwind:"$items"},
{$group: { _id:"$items.id",count:{$sum:"$qty"}}}
])
В сочетании с запросом о количестве товаров каждого товара на складе вы можете узнать, нужно ли вам что-то заказывать (вы должны выполнить этот расчет в своем коде, в MongoDB нет простого способа сделать это).
Видите ли, с "небольшим" изменением вы получите ответы на множество вопросов.
И это в основном, как это работает. С помощью реляционных данных вы моделируете свои данные так, чтобы сущности отражались правильно, а затем спрашиваете
Как я могу получить свои ответы из этих данных?
В NoSQL вообще и особенно с MongoDB вы сначала спросите
На какие вопросы мне нужно получить ответ?
и смоделируйте свои данные соответственно. Тонкое, но важное отличие.