MongoDB: 如何索引未知字段

MongoDB: How to index unknown fields

我们正在存储结构未定义的文档。我的意思是,它有一个基本结构(idusercreationTimestamp),但也有一个 Map<String, Object> values 字段,我们可以在其中存储任何结构:

public class Metadata {
    private String id;
    private String user;
    private Date creationTimestamp;
    private Map<String, Object> values;
}

示例:

> db.metadata.find();
{
    "_id" : "Doc2Ref2Mdt1",
    "user" : "user1",
    "creationTimestamp" : ISODate("2018-09-24T12:20:56.958Z"),
    "values" : {
        "ambit" : "ctti",
        "departament" : "economia"
    }
},
{
    "_id" : "Doc1Ref2Mdt1",
    "user" : "user2",
    "creationTimestamp" : ISODate("2018-09-24T12:20:56.169Z"),
    "values" : {
        "date" : ISODate("2018-09-24T12:20:56.171Z"),
        "number" : 16,
        "address" : {
        "street" : "Av. Diagonal",
        "location" : "barcelona",
        "credentials" : [
        {
            "password" : "pwd",
            "login" : "main"
        },
        {
            "password" : "pwd",
            "login" : "other",
            "creation" : ISODate("2018-09-24T12:20:56.171Z")
        }],
        "contact" : "contact name",
        "tags" : ["tag1", "tag2"}]
    }
}

所以,你可以看到values可以存储任何结构。

我想知道 mongodb 是否能够自动索引所有这些。

我的意思是,当一个新字段 "added" 变成 values 时,例如 values.newfield 它会自动编入索引。

有什么想法吗?

您可以在子文档上创建索引,新字段将自动添加,

但是

要在您的查询中使用此索引,您必须提供 完整且有序的 文档作为参数。

例如,您的示例:

db.metadata.createIndex({"values",1});

db.metadata.find("values.ambit":"ctti")

==> 不会使用索引,但会 return 第一个文档。

db.metadata.find(values:{ambit:"ctti"})

==> 会用到索引,但是return没有文件。

db.metadata.find(values:{"departament" : "economia", ambit:"ctti"})

==> 会使用索引,但是return 没有文档,因为字段顺序不同。

db.metadata.find(values:{ambit:"ctti", "departament" : "economia"})

==> 会用到索引,return和return第一个文件。

无法以您想要的方式实现。

您可以尝试 text index on all fields 然后进行实际查询。单独的文本搜索可能会导致误报匹配,但与普通查询聚合后,它将减少要扫描的数据集,并且在大多数情况下会加快速度。

需要牢记以下限制:

  • 只有字符串字段会被索引,例如.find({ $text: { $search: "2018-09-24" } }) 不会 return 任何东西。 .find({ $text: { $search: "16" } })
  • 也不会
  • 只有全词查询,即没有正则表达式。您将需要使用 language: "none" 来保留停用词并且不要使用词干。 .find({ $text: { $search: "barcel" } }) 之类的查询不会找到第二个文档。

第一个限制可以通过在写入时将 values 映射序列化到字符串字段来解决,如果您控制所有写入。那么你只需要在这个字段上创建一个文本索引。

从 4.2 版开始 MongoDB 现在支持所谓的 通配符索引

假设您收集具有以下结构的对象

{ "userMetadata" : { "likes" : [ "dogs", "cats" ] } }
{ "userMetadata" : { "dislikes" : "pickles" } }
{ "userMetadata" : { "age" : 45 } }
{ "userMetadata" : "inactive" }

您可以添加这个索引:

db.userData.createIndex( { "userMetadata.$**" : 1 } )

该索引将支持如下查询:

db.userData.find({ "userMetadata.likes" : "dogs" })
db.userData.find({ "userMetadata.dislikes" : "pickles" })
db.userData.find({ "userMetadata.age" : { $gt : 30 } })
db.userData.find({ "userMetadata" : "inactive" })

您也可以查看文档。 https://docs.mongodb.com/manual/core/index-wildcard/