MongoDB: 如何索引未知字段
MongoDB: How to index unknown fields
我们正在存储结构未定义的文档。我的意思是,它有一个基本结构(id
、user
和 creationTimestamp
),但也有一个 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/
我们正在存储结构未定义的文档。我的意思是,它有一个基本结构(id
、user
和 creationTimestamp
),但也有一个 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/