MongoDB中具有动态键字段的JSON模式
想要对mongodb集合中存储的对象提供i18n支持吗 目前我们的模式如下:MongoDB中具有动态键字段的JSON模式,mongodb,jsonschema,Mongodb,Jsonschema,想要对mongodb集合中存储的对象提供i18n支持吗 目前我们的模式如下: { _id:“id” 姓名:“姓名” 本地化:[{ 兰:“恩,我们”, 姓名:“英语姓名” }, { lan:“zh TW”, 姓名:“繁体中文姓名” }] } 但是我的想法是“lan”字段是唯一的,我可以把这个字段作为一个键来使用吗,所以结构会很简单 { _id:“id” 姓名:“姓名” 本地化:{ “en US”:“英语名称”, “zh TW”:“姓名用繁体中文” } } 这将更整洁,更容易解析(只需本地化[语
{
_id:“id”
姓名:“姓名”
本地化:[{
兰:“恩,我们”,
姓名:“英语姓名”
}, {
lan:“zh TW”,
姓名:“繁体中文姓名”
}]
}
但是我的想法是“lan”字段是唯一的,我可以把这个字段作为一个键来使用吗,所以结构会很简单
{
_id:“id”
姓名:“姓名”
本地化:{
“en US”:“英语名称”,
“zh TW”:“姓名用繁体中文”
}
}
这将更整洁,更容易解析(只需本地化[语言]就可以得到我想要的特定语言的值)
但问题是:这是在MongoDB中存储数据的良好实践吗?如何通过json模式检查?显然,第二个模式示例更适合您的任务(当然,如果
lan
字段如您所述是唯一的,这对我来说也是正确的)
从字典/关联数组/映射/无论它在您的语言中被称为什么,
获取元素要比扫描整个值数组便宜得多(在当前情况下,从存储大小的角度来看,它也非常有效)(请记住,所有字段都按原样存储在MongoDB中,因此每个记录都保存json字段的整个键名,而不是它的表示或索引或其他内容)
我的经验表明,MongoDB已经足够成熟,可以用作应用程序的主存储,即使是在高负载情况下(无论它是什么意思;)),主要问题是如何对抗数据库级锁(好吧,我们将等待承诺的表级锁,我希望它会加快MongoDB的速度),但如果您的MongoDB集群构建得不好,则可能会丢失数据(深入互联网上的文档和文章以获取更多信息)
至于模式检查,您必须在插入记录之前通过应用程序端的编程语言进行检查,是的,这就是为什么Mongo被称为无模式的
将值作为键不是一种好的做法。语言代码是值,正如您所说,您无法根据模式验证它们。它会再次进行查询这是不可能的。例如,您无法确定是否有“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_代表_name',lan:'en-US'})
- 使用相同索引查询每个id的所有版本:
db.so.find({your_id:id\u for_name})
- 而且更容易更新特定语言的翻译:
db.so.update( { your_id: "id_for_name", lan: 'en-US' }, { $set: { name: "ooga" } } )
这两个点在您建议的模式中都是不可能的。在这种情况下,对象必然比数组更好:支持向上插入到集合中。例如,如果您希望将具有
名称的项更新为具有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' })
(注意:$
位置运算符不支持数组加高。)胡说八道。“单独查询翻译”:db.so.find({'localization.lan':'en-US'})
(这里可以使用索引),或db.so.find({'localization.en-US':{$exists:true}})
“查询每个id的所有翻译”:db.so.find({{u-id:'id'})
如果你只需要翻译,请添加一个字段说明符。“更新特定翻译”:db.so.Update({u-id:'id','localization.lan':'en-US'},{$set:{'localization.$.name':'ooga'})
或db.so.Update({u-id:'id','localization.en-US':{$exists:true},{$set:{'localization.en-US.name':'ooga'})
。每种方法都有其独特的特点;没有一种是“不良做法”。