考虑以下数据结构,一旦存储在数据库系统(rdbms或nosql)中,QUERY数据会更好吗?元数据字段中的字段是用户定义的,并且因用户而异。可能的值包括字符串,数字,“日期”或甚至数组。
var file1 = {
id: 123, name: "mypicture", owner: 1
metadata: {
people: ["Ben", "Tom"],
created: 2013/01/01,
license: "free",
rating: 4
...
},
tags: ["tag1", "tag2", "tag3", "tag4"]
}
var file2 = {
id: 155, name: "otherpicture", owner: 1
metadata: {
people: ["Tom", "Carla"],
created: 2013/02/02,
license: "free",
rating: 4
...
},
tags: ["tag4", "tag5"]
}
var file1OtherUser = {
id: 345, name: "mydocument", owner: 2
metadata: {
autors: ["Mike"],
published: 2013/02/02,
…
},
tags: ["othertag"]
}
我们的用户应该能够搜索/过滤他们的文件:
结果应该像在OS X中使用智能文件夹一样进行过滤。在上载/存储文件之前定义各个元数据字段。但是之后它们也可能发生变化,例如用户1可以将元数据字段“people”重命名为“cast”。
答案 0 :(得分:0)
正如@WiredPrairie所说,metadata
字段内的字段看起来是变量,可能取决于用户输入的内容:
用户1可以将元数据字段“people”重命名为“cast”。
MongoDB无法创建变量索引,只需说metadata
中的每个新字段都会添加到复合索引中,但是你可以这样做一个键值类型结构:
var file1 = {
id: 123, name: "mypicture", owner: 1
metadata: [
{k: people, v:["Ben", "Tom"]},
{k: created, v:2013/01/01},
],
tags: ["tag1", "tag2", "tag3", "tag4"]
}
这是执行此操作的一种方法,允许您在k
字段内动态地对v
和metadata
进行索引。然后你会这样查询:
db.col.find({metadata:{$elemMatch:{k:people,v:["Ben"]}}})
然而,这确实引入了另一个问题。 $elemMatch
适用于顶层,而非嵌套元素。想象一下,你想找到“Ben”是people
之一的所有文件,你不能在这里使用$elemMatch
所以你必须这样做:
db.col.find({metadata.k:people,metadata.v:"Ben"})
此查询的直接问题在于MongoDB查询的方式。当它查询metadata
字段时,它会说:其中一个字段“k”等于“people”而字段“v”等于“Ben”。
由于这是一个多值字段,您可能遇到问题,即使“Ben”不在人员列表中,因为他存在于metadata
的另一个字段中,您实际上选择了错误的文档;即此查询将会启动:
var file1 = {
id: 123, name: "mypicture", owner: 1
metadata: [
{k: people, v:["Tom"]},
{k: created, v:2013/01/01},
{k: person, v: "Ben"}
],
tags: ["tag1", "tag2", "tag3", "tag4"]
}
解决此问题的唯一真正方法是将动态字段分解为另一个没有此问题的集合。
这会产生一个新问题,您无法再通过单次往返获得完整文件,也无法一次性聚合文件行及其用户定义字段。总而言之,你通过这种方式失去了很多能力。
话虽如此,您仍然可以执行相当多的查询,即:
使用此架构仍然可以实现所有这些。
哪个更好-RDBMS或NoSQL;这里很难说,我会说如果做得对,两者都可以很好地查询这个结构。