DocumentDb SQL - 在DocumentClient

时间:2017-10-25 16:39:00

标签: azure azure-cosmosdb azure-functions

我尝试使用DocumentClient从AzureFunction运行以下查询:

SELECT 
  *
FROM
  c
where
  ARRAY_CONTAINS(
    c.facilities, 
    { \"id\": \"d742df06-5343-44cf-55b5-bce660ccb907\" },
    true
  )

(为了便于阅读,此处添加了换行符)

如果我从Azure门户中的查询资源管理器运行此查询,它可以很好地工作。

如果我从Azure Function运行它,我会得到以下异常:

{
  "errors":[
    {
      "severity":"Error",
      "location":{
        "start":22,
        "end":106
      },
      "code":"SC2050",
      "message":"The ARRAY_CONTAINS function requires 2 argument(s)."
    }
  ]
}

我个人认为,这是从Azure功能运行的事实是无关紧要的 - 虽然我没有必要从本地运行的应用程序尝试它,我相信我会得到相同的响应,因为它似乎这个错误来自DocumentClient或DocumentDb SQL引擎本身。我在同一个项目中运行了另一个Azure CosmosDbTrigger函数,唯一的区别是触发函数和查询本身的集合 - 另一个不使用ARRAY_CONTAINS()。

上面的查询是直接从QuerySpec对象(来自调试器)复制的,我将进入以下方法:

dbClient.CreateDocumentQuery<Document>(uri, query)

我已经确认uri对我的集合有正确的URI,查询包含上面的查询。我目前将文档中的ID值传递给Azure Functions触发器,替换为您在上面看到的硬编码值。

我试图使用ARRAY_CONTAINS的三参数形式,因为我只需要ID值来匹配。

为什么我收到此错误的任何想法?

更新#1

好的,我决定打开我的方便花花公子的LinqPad副本并编写一个小程序来测试相同的代码。我将Azure函数中的相关代码行复制并粘贴到LinqPad中并尝试运行它。这次它像冠军一样工作。

Dump of query from LinqPad

所以这似乎从方程中删除了DocumentClient,至少从本地机器中删除了。关于为什么它会在Azure函数中爆炸的任何想法?

更新2

这是功能代码的略微编辑版本。要在此发布,我已经更改了类中某些静态变量的值。除此之外,这与生成下面的调试器输出的代码相同。

public static class DeleteItem
{
    private static string OtherCollection = "MyOtherCollection";
    private static string MainCollection = "MainCollection";

    [FunctionName("DeleteItem")]
    public static async Task Run(
        [CosmosDBTrigger(
            "myDb",
            "MainCollection",
            ConnectionStringSetting = "DocDbConnectionString"
        )] IReadOnlyList<Document> documents,
        TraceWriter log)
    {
        try
        {
            using (var dbClient = new DocumentClient(new Uri(Config.DocDbEndpoint), Config.DocDbKey))
            {
                foreach (var doc in documents)
                {
                    // Get the ID of the document
                    var itemId = doc.Id;

                    try
                    {
                        // Determine if the doc should be deleted
                        var isDeleted = doc.GetPropertyValue<bool?>("isDeleted");
                        if (!isDeleted.HasValue || !isDeleted.Value) continue;

                        // Query the other collection to see if this item is being used
                        var uri = UriFactory.CreateDocumentCollectionUri(Config.DocDbName, OtherCollection);
                        var paramsList = new SqlParameterCollection {
                            new SqlParameter
                            {
                                Name = "@itemId",
                                Value = itemId
                            }
                        };
                        var query = new SqlQuerySpec("SELECT * FROM c where ARRAY_CONTAINS(c.facilities, { id: @itemId }, true)", paramsList);
                        var result = dbClient.CreateDocumentQuery<Document>(uri, query).ToList();


                        // If the item wasn't found in the other collection, then go ahead and completely remove it
                        if (!result.Any())
                        {
                            uri = UriFactory.CreateDocumentUri(Config.DocDbName, MainCollection, itemId);
                            await dbClient.DeleteDocumentAsync(uri);
                            log.Info($"Item (Id = {itemId}) has been completely removed from the database.");
                        }

                        // Otherwise just log that we're keeping this as a soft-delete
                        else
                        {
                            log.Info($"Item (Id = {itemId}) stored as soft-delete.");
                        }
                    }
                    catch (Exception ex)
                    {
                        log.Error($"Unable to delete item (Id = {itemId})", ex);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            log.Error("Unable to perform delete operation", ex);
        }
    }
}

在调试器中运行我在查询执行(未编辑)之前看到以下内容:

Screenshot of watch before query execution

运行查询后,控制传递到catch块,我得到以下内容(未经编辑):

Screenshot of watch in catch block

以下是该例外(未经编辑)的一些细节:

Exception Message: {"errors":[{"severity":"Error","location":{"start":22,"end":75},"code":"SC2050","message":"The ARRAY_CONTAINS function requires 2 argument(s)."}]}

Inner Exception Message: Exception from HRESULT: 0x800A0B00

Stack Trace:
   at Microsoft.Azure.Documents.Query.QueryPartitionProvider.GetPartitionedQueryExecutionInfoInternal(SqlQuerySpec querySpec, PartitionKeyDefinition partitionKeyDefinition, Boolean requireFormattableOrderByQuery, Boolean isContinuationExpected)
   at Microsoft.Azure.Documents.Query.DocumentQueryExecutionContextBase.<GetPartitionedQueryExecutionInfoAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Documents.Query.DocumentQueryExecutionContextFactory.<CreateDocumentQueryExecutionContextAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Documents.Linq.DocumentQuery`1.<CreateDocumentQueryExecutionContextAsync>d__12.MoveNext()

如果我接受该查询并且Id和我将它们转储到Azure Portal的查询资源管理器中,我会得到以下结果(通过删除ID值和一个人的名字来编辑):

Query running in Azure Portal Query Explorer

此时,我有点沮丧。我已经尝试过调整查询字符串,确保它不像一个额外的引用,不匹配的引号或类似的其他奇怪的东西。我在这里没有想法。

0 个答案:

没有答案