希望对存储在mongodb集合中的对象提供i18n支持
目前我们的架构如下:
{
_id: "id"
name: "name"
localization: [{
lan: "en-US",
name: "name_in_english"
}, {
lan: "zh-TW",
name: "name_in_traditional_chinese"
}]
}
但我的想法是字段“lan”是唯一的,我可以只使用此字段作为键,因此结构将是
{
_id: "id"
name: "name"
localization: {
"en-US": "name_in_english",
"zh-TW": "name_in_traditional_chinese"
}
}
这将更整洁,更容易解析(只是本地化[语言]将获得我想要的特定语言的价值)。
但问题是:这是在MongoDB中存储数据的一个好方法吗?以及如何通过json-schema检查?
答案 0 :(得分:7)
将值作为键是不好的做法。语言代码是值,正如您所说,您无法根据模式验证它们。它使查询不可能。例如,您无法弄清楚是否为“nl-NL”进行语言翻译,因为您无法与键进行比较,也无法轻松将其编入索引。您应始终具有描述性密钥。
然而,正如您所说,将语言作为键使得将数据拉出更容易,因为您可以通过['nl-NL']
(或者您的语言的任何语法)访问它。
我会建议另一种模式:
{
your_id: "id_for_name"
lan: "en-US",
name: "name_in_english"
}
{
your_id: "id_for_name"
lan: "zh-TW",
name: "name_in_traditional_chinese"
}
现在你可以:
{ your_id: 1, lan: 1 }
设置索引,以便快速查找db.so.find( { your_id: "id_for_name", lan: 'en-US' } )
db.so.find( { your_id: "id_for_name" } )
还可以更轻松地更新特定语言的翻译:
db.so.update(
{ your_id: "id_for_name", lan: 'en-US' },
{ $set: { name: "ooga" } }
)
使用您建议的架构时,这些点都不可能。
答案 1 :(得分:1)
显然第二个模式示例对你的任务来说要好得多(当然,如果你提到的lan
字段是唯一的,那对我来说也是如此)。
从dictionary/associated array/mapping/whatever_it_is_called_in_your_language
获取元素比扫描整个数组值便宜得多(在当前情况下,从存储大小的角度来看它也非常有效(请记住,所有字段都存储在MongoDB as-is
中) ,所以每个记录都包含json字段的整个键名,而不是它的表示或索引或其他任何内容。
我的经验表明,MongoDB已经足够成熟,可以用作应用程序的主存储器,即使是在高负载(无论它意味着什么;)),主要问题是你如何对抗数据库级锁(嗯,我们将等待承诺的表级锁,它会强制MongoDB我希望更多),尽管如果你的MongoDB集群构建得很糟糕,数据丢失是可能的(通过Internet挖掘文档和文章以获取更多信息)。
至于模式检查,你必须在插入记录之前通过应用程序端的编程语言来实现,是的,这就是为什么称Mongo为schemaless
。
答案 2 :(得分:0)
有一种情况是对象必然比数组更好:支持将upserts放入集合中。例如,如果要更新具有name
'item1'的项目以具有val
100,或者如果一个项目不存在则插入此类项目,则只需一次原子操作。使用数组,您必须执行两个操作之一。给出类似
{ _id: 'some-id', itemSet: [ { name: 'an-item', val: 123 } ] }
你有命令
// Update:
db.coll.update(
{ _id: id, 'itemSet.name': 'item1' },
{ $set: { 'itemSet.$.val': 100 } }
);
// Insert:
db.coll.update(
{ _id: id, 'itemSet.name': { $ne: 'item1' } },
{ $addToSet: { 'itemSet': { name: 'item1', val: 100 } } }
);
您必须首先询问是否需要提前知道哪些内容,这可能会加剧竞争条件,除非您实施某些版本控制。使用对象,您只需执行
db.coll.update({
{ _id: id },
{ $set: { 'itemSet.name': 'item1', 'itemSet.val': 100 } }
});
如果这是一个用例,那么你应该采用对象方法。一个缺点是查询特定名称需要扫描。如果还需要,您可以添加一个专门用于索引的单独数组。这是与MongoDB的权衡。 Upserts将成为
db.coll.update({
{ _id: id },
{
$set: { 'itemSet.name': 'item1', 'itemSet.val': 100 },
$addToSet: { itemNames: 'item1' }
}
});
然后查询将只是
db.coll.find({ itemNames: 'item1' })
(注意:$
位置运算符不支持数组upsert。)