MongoDB对整个嵌入文档值的范围查询

MongoDB对整个嵌入文档值的范围查询,mongodb,indexing,bson,Mongodb,Indexing,Bson,假设我们有一个索引为{tag:1}的集合foo,其中tag是一个单一的键值对(在我的实际用例中有更多的细节,但我正在尝试提取问题): 当我查询{tag:{$gte:{baz:MinKey()}}}时,它返回两个文档(意外) 当我查询{tag:{$gte:{baz:}}}时,它只返回{u id:2,tag:{baz:{baz}}}(预期) 根据,BSON对象按顺序排列:1)按字段名,2)按字段值 那么为什么{tag:{$gte:{baz:MinKey() 不存在的字段 比较将不存在的字段视为空的B

假设我们有一个索引为
{tag:1}
的集合
foo
,其中
tag
是一个单一的键值对(在我的实际用例中有更多的细节,但我正在尝试提取问题):

当我查询
{tag:{$gte:{baz:MinKey()}}}
时,它返回两个文档(意外)

当我查询
{tag:{$gte:{baz:}}}
时,它只返回
{u id:2,tag:{baz:{baz}}}
(预期)

根据,BSON对象按顺序排列:1)按字段名,2)按字段值


那么为什么
{tag:{$gte:{baz:MinKey()

不存在的字段

比较将不存在的字段视为空的BSON对象。因此,对文档{}和{a:null}中的a字段进行排序时,将按照排序顺序将文档视为等价的

这说明对不存在的字段和设置为null的字段进行了特殊处理

为了使文档
{}
{a:null}
在排序顺序上是等效的,排序算法必须考虑缺少的排序字段,并且具有
null
的值

如果显式添加缺少的字段,只是为了查看它的外观,则排序更有意义

应用于
{id:1,tag:{bar:bar}}
的过滤器
{tag:{$gte:{baz:MinKey()}}}
实质上是将
{baz:MinKey()}
{baz:null,bar:bar}
进行比较

在您链接的文档顶部附近,它指出
MinKey
小于
null
,因此这是正确的顺序

编辑

通常,当字段名本身不是数据时,查询效率最高。就表格数据库而言,哪一列包含“baz”

模式中的细微更改将简化这种类型的查询。使用
{k:tagname,v:tagvalue}
代替
{k:tagname,v:tagvalue}
。然后,您可以索引
tag.k
和/或
tag.v
,并在
tag.k
上查询以查找所有带有“baz”标记的文档,使用不等运算查询标记将更直观

db.collection.find({"tag.k":{$gte:"baz"}})
可以使用elemMatch之类的工具进行精确匹配

db.collection.find({tag: {$elemMatch:{k:"baz",v:"BAZ"}}})
如果确实需要返回的文档包含
{tagname:tagvalue}
,则
$arrayToObject
聚合运算符可以执行以下操作:

db.collection.aggregate([
  {$match: {
      "tag.k": {$gte: "baz"}
  }},
  {
    $addFields: {
      tag: {$arrayToObject: [["$tag"]]}
  }}
])

标记是一个对象<代码>“tag.baz”
是一个字段。我认为您是在比较字段,而不是对象。不,我试图比较整个嵌入文档/对象。例如,
{someStringA:“abc”}
小于
{someStringB:“abc”}
,因为
someStringA
小于
someStringB
。另外,
{someInt:123}
小于
{someInt:456}
,因为
someInt
=
someInt
但是
123
小于
456
在MongoDB手册中有一些示例,说明了嵌入式文档和嵌入式文档的查询字段的精确匹配。我认为这可能是一个答案,但是,由于我们将整个嵌入文档视为一个值,因此它也可能不是答案。我在mongo提出了一个问题,如果您愿意的话:特别是为什么我认为这可能不是答案,因为我们正在查询/比较整个嵌入文档作为一个值,根据文档链接,应该比较字段名。我相信BSON文档也维护订单。同意,唯一的方法是将一个字段和一个包含空值的字段缺少相同的文档排序,认为两个文档中都存在字段,隐式地将缺少的字段添加到第二个操作数。我不知道这是否一定是真的。如果BSON文档被视为键-值对的有序列表(我认为它们是),那么它们甚至可以与缺少的字段进行比较。序列化BSON是kv对的有序列表。字段按添加到文档中的顺序存储。i、 e.
{a:1,b:1}
不等于
{b:1,a:1}
。在内存中排序时,将根据提供的排序规范生成排序键,因此排序键文档中的字段将按相同顺序添加。
db.collection.aggregate([
  {$match: {
      "tag.k": {$gte: "baz"}
  }},
  {
    $addFields: {
      tag: {$arrayToObject: [["$tag"]]}
  }}
])