在 Azure Cosmos DB 中使用没有默认索引策略的 sort() 游标方法 MongoDB API
Using the sort() cursor method without the default indexing policy in Azure Cosmos DB for MongoDB API
对于 MongoDB API(版本 3.4)的 Cosmos DB,以下查找查询与游标排序方法的组合似乎表现不正确:
db.test.find({"field1": "value1"}).sort({"field2": 1})
如果满足以下所有条件,则会发生错误:
- 放弃了默认索引策略 - 无论之后是否使用 createIndex() 创建了自定义索引。
- find() 查询没有 return 任何文档(Find(filter).Count() == 0)
- 定义排序顺序的排序文档仅包含一个字段。这个字段是否存在或是否已被索引并不重要。在排序文档中使用两个字段 returns 0 命中,这是正确的行为。
如果满足以下所有条件,也会出现此错误:
- 默认索引策略已被丢弃
- find() 查询return一个或多个文档
- 排序文档只包含一个字段。该字段尚未编入索引。
错误信息:
The index path corresponding to the specified order-by item is excluded.
故障仅在使用 CosmosDB 时出现,使用原生 MongoDB(mongoDB Atlas,v4.0)它可以正常运行。
Azure Cosmos DB for MongoDB API 使用 MongoDB 3.4 wire 协议(预览功能)。 MongoDB C#/.NET 驱动程序和 mongo shell.
都会出现此问题
此外,该问题仅出现在 find() 中。包含 $match 和 $sort 的等效聚合管道行为正确。
复制
- 使用 "Azure Cosmos DB for MongoDB API" 创建一个 Azure Cosmos DB 帐户。启用预览功能MongoDB3.4(3.2版本未测试)
- 创建新数据库
- 创建新集合,定义分片键
- 删除默认索引策略(使用 db.test.dropIndexes() )
- (可选)创建新的自定义索引
- (可选)插入文档
在 mongo shell 中执行命令(或使用 mongoDB C#/.NET 驱动程序的等效代码):
db.test.find({"field1": "value1"}).sort({"field2": 1})
预期结果
符合查询条件的所有文档。如果有 none,则不应 return 编辑任何文档。
实际结果
错误:错误:{
“_t”:"OKMongoResponse",
"ok" : 0,
"code" : 2,
"errmsg" : "Message: {\"错误\":[\"The index path corresponding to the specified order-by item is excluded.\"]}\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:Document,OperationType:Query\r\n,SDK:Microsoft.Azure.Documents.Common/2.4.0.0” , [...]
解决方法
向排序文档添加额外的 "dummy" 字段可防止错误:
db.test.find({"field1": "value1"}).sort({"field2": 1, "dummyfield": 1}).count()
解决方法并不令人满意。它可能会伪造结果。
是我做错了什么,还是 Cosmos DB 的行为有缺陷?
根据微软的支持,需要在排序的字段上创建索引。可以删除默认索引并创建自定义索引。至于每次添加新字段时不修改索引的问题,除了执行客户端排序之外没有其他选择。不幸的是,客户端排序会在客户端占用大量 CPU 内存,而当您要索引更多字段时,索引排序会起作用。
因此我没有找到真正令人满意的解决方案:
- 使用默认索引策略。然而,这会导致一个巨大的索引。
- 索引所有需要排序的元素。每次必须对新元素进行索引时,都会导致手动修改索引策略。
- 只使用客户端排序。在我看来,这会导致 MongoDB 功能受到严重限制。
- 使用聚合框架而不是查找方法。这会导致复杂性和流量增加。
- 正在迁移到本机 MongoDB。
db.collection.createIndex ({ "$**" : 1 });
对于 MongoDB API(版本 3.4)的 Cosmos DB,以下查找查询与游标排序方法的组合似乎表现不正确:
db.test.find({"field1": "value1"}).sort({"field2": 1})
如果满足以下所有条件,则会发生错误:
- 放弃了默认索引策略 - 无论之后是否使用 createIndex() 创建了自定义索引。
- find() 查询没有 return 任何文档(Find(filter).Count() == 0)
- 定义排序顺序的排序文档仅包含一个字段。这个字段是否存在或是否已被索引并不重要。在排序文档中使用两个字段 returns 0 命中,这是正确的行为。
如果满足以下所有条件,也会出现此错误:
- 默认索引策略已被丢弃
- find() 查询return一个或多个文档
- 排序文档只包含一个字段。该字段尚未编入索引。
错误信息:
The index path corresponding to the specified order-by item is excluded.
故障仅在使用 CosmosDB 时出现,使用原生 MongoDB(mongoDB Atlas,v4.0)它可以正常运行。
Azure Cosmos DB for MongoDB API 使用 MongoDB 3.4 wire 协议(预览功能)。 MongoDB C#/.NET 驱动程序和 mongo shell.
都会出现此问题此外,该问题仅出现在 find() 中。包含 $match 和 $sort 的等效聚合管道行为正确。
复制
- 使用 "Azure Cosmos DB for MongoDB API" 创建一个 Azure Cosmos DB 帐户。启用预览功能MongoDB3.4(3.2版本未测试)
- 创建新数据库
- 创建新集合,定义分片键
- 删除默认索引策略(使用 db.test.dropIndexes() )
- (可选)创建新的自定义索引
- (可选)插入文档
在 mongo shell 中执行命令(或使用 mongoDB C#/.NET 驱动程序的等效代码):
db.test.find({"field1": "value1"}).sort({"field2": 1})
预期结果
符合查询条件的所有文档。如果有 none,则不应 return 编辑任何文档。
实际结果
错误:错误:{ “_t”:"OKMongoResponse", "ok" : 0, "code" : 2, "errmsg" : "Message: {\"错误\":[\"The index path corresponding to the specified order-by item is excluded.\"]}\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:Document,OperationType:Query\r\n,SDK:Microsoft.Azure.Documents.Common/2.4.0.0” , [...]
解决方法
向排序文档添加额外的 "dummy" 字段可防止错误:
db.test.find({"field1": "value1"}).sort({"field2": 1, "dummyfield": 1}).count()
解决方法并不令人满意。它可能会伪造结果。
是我做错了什么,还是 Cosmos DB 的行为有缺陷?
根据微软的支持,需要在排序的字段上创建索引。可以删除默认索引并创建自定义索引。至于每次添加新字段时不修改索引的问题,除了执行客户端排序之外没有其他选择。不幸的是,客户端排序会在客户端占用大量 CPU 内存,而当您要索引更多字段时,索引排序会起作用。
因此我没有找到真正令人满意的解决方案:
- 使用默认索引策略。然而,这会导致一个巨大的索引。
- 索引所有需要排序的元素。每次必须对新元素进行索引时,都会导致手动修改索引策略。
- 只使用客户端排序。在我看来,这会导致 MongoDB 功能受到严重限制。
- 使用聚合框架而不是查找方法。这会导致复杂性和流量增加。
- 正在迁移到本机 MongoDB。
db.collection.createIndex ({ "$**" : 1 });