MongoDB :如何索引Map的键

2022-09-04 19:56:57

在Java中,我有一个对象看起来像这样:

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();

这应该读找到我的MyDoc文档,其中有一个带有密钥“4fda4993eb14ea4a4a4a149c04”和值“已处理”的props。

我在集合中存储了数百万个MyDoc文档,因此我需要对someProps嵌入对象的键进行有效的索引。

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

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

如何在一些Props上索引映射键?我需要不同的文档结构吗?

重要提示:

1 .某些驱动程序只能有一个元素具有相同的键。例如:

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

将无效,因为4f56a5c4b6f621f092b00525在Map中找不到两次(因此首先使用Map)

2 .我还需要有效地更新一些Props,只更改值(例如:将“4fda4993eb14ea4a4a4a149c04”:“已处理”更改为“4fda4993eb14ea4a4a149c04”:“已取消”)

我有哪些选择?

谢谢。


答案 1

如果你想保持你的属性嵌入,你也可以使用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})

这与 Sergio 的建议非常接近,但您的数据仍将是单个集合中的一个文档。


答案 2

如何像这样构建文档:

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

这样做的三个优点是:

  1. 通过将查询从“someProps.4fda4993eb14ea4a4a4a149c04”,“已处理”翻转为“someProps.PROCESSED”,“4fda4993eb14ea4a4a4a149c04”,可以查看是否处理了某些对象

  2. 您可以在“someProps.TODO”上创建一个索引,在“someProps.PROCESSED”上创建另一个索引(您无法在多个并行数组上创建复合索引,但听起来您会按单个状态进行查询,对吗?

  3. 您可以原子地将文档从一种状态移动到另一种状态,如下所示:

.

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