0

简化示例和问题

为了尽可能简单,我将直接举一个例子:

foo具有多键索引的集合{searchTags: 1}

{_id: 1, searchTags: [{bar: "BAR"}]}
{_id: 2, searchTags: [{baz: "BAZ"}]}

我正在尝试使用baz字段键获取所有嵌入式文档(不使用$exists- 我可以稍后尝试解释原因)。为什么

{searchTags: {$elemMatch: { $gte: { baz: MinKey() }, $lte: { baz: MaxKey() }}}}

返回两个文件(不是首选),但是

{searchTags: {$elemMatch: { $gte: { baz: "" }, $lte: { baz: MaxKey() }}}}

只返回{_id: 2, searchTags: [{baz: "BAZ"}]}(首选)?

旁注:快速架构细节可能会避免“你在做什么?” 问题

  • 这些是简单的嵌入文档,只有 1 个键值对。
  • 这些值可以是多种类型,而不仅仅是字符串(否则,我将只使用前缀字符串数组而不是嵌入文档)
  • 由于嵌入式文档是单一的键值对,我可以确定性地在嵌入式文档上使用相等和比较查询。
  • 键是foo文档上的其他字段名称,值是它们的字段值。我可以索引各个字段,但它们将是部分索引并且会有很多。为了灵活性,将它们全部合并到具有多键索引的数组中是最有意义的。
  • 仍然愿意听到我为什么错了:)
4

1 回答 1

0
  • 上的索引{searchTags: 1}未用于为该查询提供服务

索引数组时,数组的每个元素都作为一个值包含在索引中。任何恰好是文档的元素都是作为整个文档的索引,它不会按字段细分。我希望如果您使用 运行该命令explain,它会显示它是一个集合扫描。

  • MinKey 小于任何其他可能的键值,包括 null、缺失和未定义。MaxKey 也是如此

快速演示:

> db.collection.insertMany([
 {_id: 1, searchTags: [{bar: "BAR"}]},
 {_id: 2, searchTags: [{baz: "BAZ"}]} 
])
{ "acknowledged" : true, "insertedIds" : [ 1, 2 ] }

> db.collection.aggregate([
  {$unwind: "$searchTags"},
  {$addFields: {
      baztype: {$type: "$searchTags.baz"},
      bazmin: {$gt: ["$searchTags.baz", MinKey()]},
      bazmax: {$lt: ["$searchTages.baz", MaxKey()]},
      bazstr: {$gt: ["$searchTags.baz", ""]}
   }}
])
{ "_id" : 1, "searchTags" : { "bar" : "BAR" }, "baztype" : "missing", "bazmin" : true, "bazmax" : true, "bazstr" : false }
{ "_id" : 2, "searchTags" : { "baz" : "BAZ" }, "baztype" : "string", "bazmin" : true, "bazmax" : true, "bazstr" : true }

您显示的第一个查询匹配,因为每个可能的值,包括未定义,都大于 MinKey 和小于 MaxKey。

您显示的第二个查询不匹配,因为运算符区分大小写,因此当提供字符串值时,只有字符串值将匹配,这不包括未定义。

  • 要查找包含字段的文档,无论类型如何,请使用$exists运算符:
db.collection.find({"searchTags.baz":{$exists:true}})
于 2020-09-30T11:03:55.277 回答