2012-06-17 54 views
3

在Java中我有一个对象,看起来像这样一个Map的键:的MongoDB:如何索引

class MyDoc { 
    ObjectId docId; 
    Map<String, String> someProps = new HashMap<String,String>(); 
} 

,当坚持到MongoDB中生成以下文件:

{ 
    "_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"), 
    "someProps" : { 
     "4fda4993eb14ea4a4a149c04" : "PROCESSED", 
     "4f56a5c4b6f621f092b00525" : "PROCESSED", 
     "4fd95a2a0baaefd1837fe504" : "TODO" 
    } 
} 

我需要查询如下。

DBObject queryObj = 
new BasicDBObject("someProps.4fda4993eb14ea4a4a149c04","PROCESSED");       
DBObject explain = 
getCollection().find(queryObj).hint("props_indx").explain(); 

应阅读找到我说有钥匙“4fda4993eb14ea4a4a149c04”一someProps的MyDoc文件和值“加工”

我有几百万存储在集合中MyDoc文件,所以我需要在高效的索引someProps嵌入式对象的键。

地图的键是事先不知道的(它们是动态生成的,它们不是一组固定的键),所以我不能为每个Props键创建一个索引。 (至少我不认为我可以纠正我,如果我错了)

我试图直接在someProps上创建索引,但查询花了很长时间。

如何索引someProps Map键? 我需要不同的文档结构吗?

重要说明:

1。只有一些具有相同关键点的元素中有一个元素。例如:

{ 
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"), 
    "someProps" : { 
     "4fda4993eb14ea4a4a149c04" : "PROCESSED", 
     "4f56a5c4b6f621f092b00525" : "PROCESSED", 
     "4f56a5c4b6f621f092b00525" : "TODO" 
    } 
} 

将是无效的,因为4f56a5c4b6f621f092b00525不能在地图(因此在第一位置使用地图)中找到两次

2。我还需要有效地更新someProps,只是改变了值(例如:改变“4fda4993eb14ea4a4a149c04”:“加工”,以“4fda4993eb14ea4a4a149c04”:“取消”)

我有哪些选择?

谢谢。

+0

看起来最好将这些设置移动到单独的文档中。 –

+0

@Sergio:你的意思是把文件somProps放在一个单独的集合中? – azpublic

+0

是的,我会从'someProps'的每个条目中创建一个单独的文档。 –

回答

1

我建议将这些属性扩展为自己的文档。所以,你的例子:

{ 
    "_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"), 
    "someProps" : { 
     "4fda4993eb14ea4a4a149c04" : "PROCESSED", 
     "4f56a5c4b6f621f092b00525" : "PROCESSED", 
     "4fd95a2a0baaefd1837fe504" : "TODO" 
    } 
} 

成为该

{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4fda4993eb14ea4a4a149c04"}, v: "PROCESSED"} 
{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4f56a5c4b6f621f092b00525"}, v: "PROCESSED"} 
{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4fd95a2a0baaefd1837fe504"}, v: "TODO"} 

这里id1是你的前母公司实体的ID(无论是应用程序或其他)和id2是财产ID。

唯一性由_id字段的属性强制执行。原子更新是微不足道的。索引是容易的

db.props.ensureIndex({'_id.id2': 1}) 

唯一的缺点是一些存储开销。

2

关于构建这样你的文件是什么:

{ 
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"), 
    "someProps" : { 
     "PROCESSED":["4fda4993eb14ea4a4a149c04","4f56a5c4b6f621f092b00525"], 
     "TODO" : ["4f56a5c4b6f621f092b00526"], 
     "CANCELLED" : [ ] 
    } 
} 

的这三个优点是:

  1. 你可以看到,如果一些对象是通过从 “someProps翻转查询处理。 4fda4993eb14ea4a4a149c04“,”PROCESSED“至 ”someProps.PROCESSED“,”4fda4993eb14ea4a4a149c04“

  2. 你可以在“someProps.TODO”上创建一个索引,在“someProps.PROCESSED”上创建另一个索引(你不能在几个并行数组上创建一个复合索引,但是这听起来像是你会以单一状态查询,对吧?

  3. 可以原子从一个状态移动到另一个文件,如下所示:

db.collection.update({"someProps.PROCESSED": "4fda4993eb14ea4a4a149c04"}, 
        {$pull:{"someProps.PROCESSED":"4fda4993eb14ea4a4a149c04"}, 
         $push:{"someProps.CANCELLED":"4fda4993eb14ea4a4a149c04"}}); 
+0

我在你的查询中采取了自由和固定的错误:) –

+0

谢谢!我可以发誓从运行它的时候将它从我的shell中剪切粘贴出来,但我想我打破它试图格式化它 - 感谢修复,以及:) –

6

如果你想保留你的属性,你也可以使用Kyle Banke在“MongoDB in Action”中提出的动态属性模式。因此,与其把道具在自己的收藏,您修改mydocs收集到这个样子:

{ 
    "_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"), 
    "someProps" : [ 
     { k: "4fda4993eb14ea4a4a149c04", v: "PROCESSED" }, 
     { k: "4f56a5c4b6f621f092b00525", v: "PROCESSED" }, 
     { k: "4fd95a2a0baaefd1837fe504", v : "TODO" } 
    ] 
} 
上嵌入文档键

然后指数:

db.mydoc.ensureIndex({'someProps.k' :1}, {'someProps.v' :1}) 

这是非常接近了什么塞尔吉奥建议,但你的数据仍然是一个集合中的一个文档。