在Azure Cosmos DB for MongoDB API中没有默认索引策略的情况下使用sort()游标方法时行为不当

时间:2019-07-11 12:02:23

标签: azure-cosmosdb azure-cosmosdb-mongoapi

对于Cosmos DB for MongoDB API(版本3.4),以下查找查询与方法游标排序的组合似乎行为不正确:

db.test.find({"field1": "value1"}).sort({"field2": 1})

如果满足以下所有条件,则会发生错误:

  • 默认索引策略被丢弃-不管之后是否使用createIndex()创建自定义索引。
  • find()查询不返回任何文档(Find(filter).Count()== 0)
  • 定义排序顺序的“排序”文档仅包含一个字段。不管该字段是否存在或已被索引。在排序文档中使用两个字段将返回0次匹配,这是正确的行为。

如果满足以下所有条件,也会发生错误:

  • 默认的索引编制策略已被放弃
  • find()查询返回一个或多个文档
  • 排序文档仅包含一个字段。该字段尚未被索引。

错误消息:

  

与指定的按订单商品对应的索引路径被排除。

仅当使用CosmosDB时,该故障才会发生,并且在本机MongoDB(mongoDB Atlas,v4.0)中,其行为正确。

使用具有MongoDB 3.4有线协议(预览功能)的Azure Cosmos DB for MongoDB API。 MongoDB C#/。NET驱动程序和mongo shell均会出现问题。

此外,该问题仅发生在find()上。包含$ match和$ sort的等效聚合管道的行为正确。

复制

  1. 使用“ Azure Cosmos DB for MongoDB API”创建一个Azure Cosmos数据库帐户。启用预览功能MongoDB 3.4(尚未测试版本3.2)。
  2. 创建一个新数据库
  3. 创建一个新集合,定义一个分片键
  4. 放弃默认的索引策略(使用db.test.dropIndexes())
  5. (可选)创建新的自定义索引
  6. (可选)插入文档

在mongo shell中执行命令(或与mongoDB C#/。NET驱动程序等效的代码):

    db.test.find({"field1": "value1"}).sort({"field2": 1})

预期结果

所有符合查询条件的文档。如果没有,则不退还任何文件。

实际结果

错误:错误:{         “ _t”:“ OKMongoResponse”,         “ ok”:0,         “代码”:2         “ errmsg”:“消息:{\”错误\“:[\”排除了与指定的按订单项对应的索引路径。“”]} \ r \ nActivityId:c50cc751-0000-0000-0000-000000000000,请求URI:/apps/[...]/,RequestStats:\ r \ nRequestStartTime:2019-07-11T08:58:48.9880813Z,RequestEndTime:2019-07-11T08:58:49.0081101Z,尝试的区域数:1 \ r \ nResponseTime:2019-07-11T08:58:49.0081101Z,StoreResult:StorePhysicalAddress:rntbd:// [...] /,LSN:359549,GlobalCommittedLsn:359548,PartitionKeyRangeId:0,IsValid:True,StatusCode:400 ,SubStatusCode:0,RequestCharge:1,ItemLSN:-1,SessionToken:-1#359549,UsingLocalLSN:True,TransportException:null,ResourceType:文档,OperationType:Query \ r \ n,SDK:Microsoft.Azure.Documents.Common /2.4.0.0“,[...]

解决方法

在排序文档中添加其他“虚拟”字段可防止错误:

db.test.find({"field1": "value1"}).sort({"field2": 1, "dummyfield": 1}).count()

解决方法不令人满意。可能会伪造结果。

我是在做错什么,还是Cosmos DB在这里有缺陷?

2 个答案:

答案 0 :(得分:4)

根据Microsoft的支持,需要在要排序的字段上创建索引。可以删除默认索引并创建自定义索引。至于每次添加新字段时都不会修改索引的问题,除了执行客户端排序之外,没有其他选择。不幸的是,客户端排序会占用客户端大量的CPU内存,而当您需要索引更多字段时,索引排序会起作用。

因此,我没有找到一个真正令人满意的解决方案:

  • 使用默认索引策略。但是,这可能会导致巨大的索引。
  • 索引所有需要排序的元素。每次必须为新元素建立索引时,都会导致对索引策略的手动修改。
  • 仅使用客户端排序。我认为这会严重限制MongoDB的功能。
  • 使用聚合框架而不是find方法。这导致复杂性和流量增加。
  • 迁移到本机MongoDB。

答案 1 :(得分:0)

db.collection.createIndex ({ "$**" : 1 });