在Java中,我有一个如下所示的对象:
class MyDoc {
ObjectId docId;
Map<String, String> someProps = new HashMap<String,String>();
}
Run Code Online (Sandbox Code Playgroud)
当持久化到MongoDB时会生成以下文档:
{
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
"someProps" : {
"4fda4993eb14ea4a4a149c04" : "PROCESSED",
"4f56a5c4b6f621f092b00525" : "PROCESSED",
"4fd95a2a0baaefd1837fe504" : "TODO"
}
}
Run Code Online (Sandbox Code Playgroud)
我需要查询如下.
DBObject queryObj =
new BasicDBObject("someProps.4fda4993eb14ea4a4a149c04","PROCESSED");
DBObject explain =
getCollection().find(queryObj).hint("props_indx").explain();
Run Code Online (Sandbox Code Playgroud)
应该读取找到MyDoc文件,其中有一些带有键"4fda4993eb14ea4a4a149c04"的someProps,值为"Processed"
我在集合中存储了数百万个MyDoc文档,因此我需要对someProps嵌入对象的键进行有效索引.
事先不知道地图的键(它们是动态生成的,它们不是一组固定的键)所以我不能为每个someProps键创建一个索引.(至少我认为如果我错了我不能纠正我)
我试图直接在someProps上创建索引,但查询需要很长时间.
如何在someProps Map键上进行索引?我需要不同的文档结构吗?
重要的笔记:
1.someProps中只有一个元素具有相同的键.例如 :
{
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
"someProps" : {
"4fda4993eb14ea4a4a149c04" : "PROCESSED",
"4f56a5c4b6f621f092b00525" : "PROCESSED",
"4f56a5c4b6f621f092b00525" : "TODO"
}
}
Run Code Online (Sandbox Code Playgroud)
因为4f56a5c4b6f621f092b00525在地图中找不到两次(因此首先使用地图)会无效
2.我还需要有效地更新someProps,只更改值(例如:将"4fda4993eb14ea4a4a149c04":"PROCESSED"更改为"4fda4993eb14ea4a4a149c04":"CANCELED")
我有什么选择?
谢谢.
如果要保持嵌入属性,还可以使用Kyle Banke在"MongoDB in Action"中提出的动态属性模式.因此,不要将道具放在自己的集合中,而是将mydocs集合修改为如下所示:
{
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
"someProps" : [
{ k: "4fda4993eb14ea4a4a149c04", v: "PROCESSED" },
{ k: "4f56a5c4b6f621f092b00525", v: "PROCESSED" },
{ k: "4fd95a2a0baaefd1837fe504", v : "TODO" }
]
}
Run Code Online (Sandbox Code Playgroud)
然后索引嵌入的文档键:
db.mydoc.ensureIndex({'someProps.k' :1}, {'someProps.v' :1})
Run Code Online (Sandbox Code Playgroud)
这与Sergio建议的非常接近,但您的数据仍然是单个集合中的一个文档.
像这样构建您的文档怎么样:
{
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
"someProps" : {
"PROCESSED":["4fda4993eb14ea4a4a149c04","4f56a5c4b6f621f092b00525"],
"TODO" : ["4f56a5c4b6f621f092b00526"],
"CANCELLED" : [ ]
}
}
Run Code Online (Sandbox Code Playgroud)
这样做的三个优点是:
您可以通过将查询从 "someProps.4fda4fda4993eb14ea4a4a149c04","PROCESSED" 翻转到 "someProps.PROCESSED", "4fda4993eb14ea4a4a149c04" 来查看是否处理了某个对象
您可以在“someProps.TODO”上创建一个索引,并在“someProps.PROCESSED”上创建另一个索引(您不能在多个并行数组上创建复合索引,但听起来您将按单个状态进行查询,对吗?
您可以自动将文档从一种状态移动到另一种状态,如下所示:
.
db.collection.update({"someProps.PROCESSED": "4fda4993eb14ea4a4a149c04"},
{$pull:{"someProps.PROCESSED":"4fda4993eb14ea4a4a149c04"},
$push:{"someProps.CANCELLED":"4fda4993eb14ea4a4a149c04"}});
Run Code Online (Sandbox Code Playgroud)
我建议将这些属性扩展到它们自己的文档中。所以你的例子:
{
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
"someProps" : {
"4fda4993eb14ea4a4a149c04" : "PROCESSED",
"4f56a5c4b6f621f092b00525" : "PROCESSED",
"4fd95a2a0baaefd1837fe504" : "TODO"
}
}
Run Code Online (Sandbox Code Playgroud)
变成这个
{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4fda4993eb14ea4a4a149c04"}, v: "PROCESSED"}
{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4f56a5c4b6f621f092b00525"}, v: "PROCESSED"}
{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4fd95a2a0baaefd1837fe504"}, v: "TODO"}
Run Code Online (Sandbox Code Playgroud)
这id1是您以前的父实体(无论是应用程序还是其他)的 id,并且id2是属性 id。
唯一性是由_id字段的属性强制执行的。原子更新是微不足道的。索引很容易
db.props.ensureIndex({'_id.id2': 1})
Run Code Online (Sandbox Code Playgroud)
唯一的缺点是一些存储开销。
| 归档时间: |
|
| 查看次数: |
4514 次 |
| 最近记录: |