【问题标题】:MongoDB: How to index unknown fieldsMongoDB:如何索引未知字段
【发布时间】:2018-09-26 08:21:37
【问题描述】:

我们正在存储具有未定义结构的文档。我的意思是,它有一个基本结构(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 是否能够自动索引所有这些。

我的意思是,当一个新字段“添加”到values 中时,例如values.newfield,它会自动被索引。

有什么想法吗?

【问题讨论】:

    标签: mongodb mongodb-query mongodb-indexes


    【解决方案1】:

    从 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/

    【讨论】:

      【解决方案2】:

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

      但是

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

      示例,与您的示例:

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

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

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

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

      ==> 将使用索引,但不返回任何文档。

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

      ==> 将使用索引,但不返回任何文档,因为字段顺序不同。

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

      ==> 将使用索引,并返回返回第一个文档。

      【讨论】:

      • 使用 mongodb compass,您可以概览您最常用的字段,这对于确定要创建的索引很有用
      • 您能否提供一些关于 mongodb 如何索引 values 字段中的任何内容的额外帮助?很难理解……
      • values 上添加新字段时,有什么方法可以按需创建索引?我不知道我是否解释得这么好……
      • 索引和索引策略是一个巨大的主题,但是没有办法“自动”创建索引。这是一件好事:如果索引提高了搜索性能,它们也会影响写入时间(每次写入时,必须更新每个相关索引)。因此,添加许多索引可能会导致性能下降,而索引必须是一个深思熟虑的策略,尤其是在大型集合上。
      • M201 online course on mongodb universitythe doc about indexes 可以作为了解更多主题的良好开端
      【解决方案3】:

      不可能以你想要的方式。

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

      需要牢记一些限制:

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

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

      【讨论】:

        猜你喜欢
        • 2019-05-22
        • 1970-01-01
        • 2020-07-20
        • 1970-01-01
        • 2011-08-28
        • 2016-11-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多