Azure Functions 使用 Binder 更新 DocumentDb 文档
Azure Functions Update DocumentDb document with Binder
我的 about Azure Functions. I need to update a document in DocumentDB using the imperative binder (Binder). I don't really understand the documentation 的后续问题,但我找不到任何示例(我或多或少找到了一种示例,即 TextWriter 示例)。文档说我可以绑定到 "out T" 我找不到这样的例子。
假设在 运行 函数之前文档看起来像这样:
{
child: {
value: 0
}
}
函数如下所示:
var document = await binder.BindAsync<dynamic>(new DocumentDBAttribute("myDB", "myCollection")
{
ConnectionStringSetting = "my_DOCUMENTDB",
Id = deviceId
});
log.Info($"C# Event Hub trigger function processed a message: document: { document }");
document.value = 100;
document.child.value = 200;
log.Info($"Updated document: { document }");
根据第二个日志记录行,文档未正确更新。子项未更新(从商店读取时存在)并添加了值。无论哪种方式,都不会保留任何内容。我试过在 function.json 中添加一个输出,但编译器抱怨它并且文档指出你不应该有任何输出。
我错过了什么?
是的,我相信这里有问题,我已经在我们的 repo 中记录了一个错误 here 来跟踪它。
要在我们修复它之前解决此问题,您可以直接绑定并使用 DocumentClient
来执行更新,例如:
public static async Task Run(
string input, Binder binder, DocumentClient client, TraceWriter log)
{
var docId = "c31d48aa-d74b-46a3-8ba6-0d4c6f288559";
var document = await binder.BindAsync<JObject>(
new DocumentDBAttribute("ItemDb", "ItemCollection")
{
ConnectionStringSetting = "<mydb>",
Id = docId
});
log.Info("Item before: " + document.ToString());
document["text"] = "Modified!";
var docUri = UriFactory.CreateDocumentUri("ItemDb", "ItemCollection", docId);
await client.ReplaceDocumentAsync(docUri, document);
}
但是,一旦您像这样直接使用 DocumentClient
,您可能会发现您可以直接将它用于您的所有操作,即您的调用。例如:
public static async Task Run(
string input, DocumentClient client, TraceWriter log)
{
var docId = "c31d48aa-d74b-46a3-8ba6-0d4c6f288559";
var docUri = UriFactory.CreateDocumentUri("ItemDb", "ItemCollection", docId);
var response = await client.ReadDocumentAsync(docUri);
dynamic document = response.Resource;
log.Info("Value: " + dynamic.text);
document.text = "Modified!";
await client.ReplaceDocumentAsync(docUri, document);
}
Mathew 的示例(使用 DocumentClient
)有效,但我想阐明另一种方法,您可以使用 Binder
和输出绑定来实现。
您遇到了两个问题:
每次您请求子对象时,Document
动态的实现似乎 return 一个新的对象实例。这与函数无关,但解释了为什么 document.child.value = 200
不起作用。您正在更新一个实际上未附加到文档的 child 实例。我将尝试 double-check 与 DocumentDb 人员进行此操作,但这令人困惑。解决此问题的一种方法是请求 JObject
而不是 dynamic
。我下面的代码就是这样做的。
正如@mathewc 所指出的,Binder
不是 auto-update 文档。我们将在他提交的问题中进行跟踪。相反,您可以使用带有 IAsyncCollector<dynamic>
的输出绑定来更新文档。 Behind-the-scenes 我们将调用 InsertOrReplaceDocumentAsync
,这将更新文档。
这是对我有用的完整示例:
代码:
#r "Microsoft.Azure.WebJobs.Extensions.DocumentDB"
#r "Newtonsoft.Json"
using System;
using Newtonsoft.Json.Linq;
public static async Task Run(string input, Binder binder, IAsyncCollector<dynamic> collector, TraceWriter log)
{
string deviceId = "0a3aa1ff-fc76-4bc9-9fe5-32871d5f451b";
dynamic document = await binder.BindAsync<JObject>(new DocumentDBAttribute("ItemDb", "ItemCollection")
{
ConnectionStringSetting = "brettsamfunc_DOCUMENTDB",
Id = deviceId
});
log.Info($"C# Event Hub trigger function processed a message: document: { document }");
document.value = 100;
document.child.value = 200;
await collector.AddAsync(document);
log.Info($"Updated document: { document }");
}
绑定:
{
"type": "documentDB",
"name": "collector",
"connection": "brettsamfunc_DOCUMENTDB",
"direction": "out",
"databaseName": "ItemDb",
"collectionName": "ItemCollection",
"createIfNotExists": false
}
我的
假设在 运行 函数之前文档看起来像这样:
{
child: {
value: 0
}
}
函数如下所示:
var document = await binder.BindAsync<dynamic>(new DocumentDBAttribute("myDB", "myCollection")
{
ConnectionStringSetting = "my_DOCUMENTDB",
Id = deviceId
});
log.Info($"C# Event Hub trigger function processed a message: document: { document }");
document.value = 100;
document.child.value = 200;
log.Info($"Updated document: { document }");
根据第二个日志记录行,文档未正确更新。子项未更新(从商店读取时存在)并添加了值。无论哪种方式,都不会保留任何内容。我试过在 function.json 中添加一个输出,但编译器抱怨它并且文档指出你不应该有任何输出。
我错过了什么?
是的,我相信这里有问题,我已经在我们的 repo 中记录了一个错误 here 来跟踪它。
要在我们修复它之前解决此问题,您可以直接绑定并使用 DocumentClient
来执行更新,例如:
public static async Task Run(
string input, Binder binder, DocumentClient client, TraceWriter log)
{
var docId = "c31d48aa-d74b-46a3-8ba6-0d4c6f288559";
var document = await binder.BindAsync<JObject>(
new DocumentDBAttribute("ItemDb", "ItemCollection")
{
ConnectionStringSetting = "<mydb>",
Id = docId
});
log.Info("Item before: " + document.ToString());
document["text"] = "Modified!";
var docUri = UriFactory.CreateDocumentUri("ItemDb", "ItemCollection", docId);
await client.ReplaceDocumentAsync(docUri, document);
}
但是,一旦您像这样直接使用 DocumentClient
,您可能会发现您可以直接将它用于您的所有操作,即您的调用。例如:
public static async Task Run(
string input, DocumentClient client, TraceWriter log)
{
var docId = "c31d48aa-d74b-46a3-8ba6-0d4c6f288559";
var docUri = UriFactory.CreateDocumentUri("ItemDb", "ItemCollection", docId);
var response = await client.ReadDocumentAsync(docUri);
dynamic document = response.Resource;
log.Info("Value: " + dynamic.text);
document.text = "Modified!";
await client.ReplaceDocumentAsync(docUri, document);
}
Mathew 的示例(使用 DocumentClient
)有效,但我想阐明另一种方法,您可以使用 Binder
和输出绑定来实现。
您遇到了两个问题:
每次您请求子对象时,
Document
动态的实现似乎 return 一个新的对象实例。这与函数无关,但解释了为什么document.child.value = 200
不起作用。您正在更新一个实际上未附加到文档的 child 实例。我将尝试 double-check 与 DocumentDb 人员进行此操作,但这令人困惑。解决此问题的一种方法是请求JObject
而不是dynamic
。我下面的代码就是这样做的。正如@mathewc 所指出的,
Binder
不是 auto-update 文档。我们将在他提交的问题中进行跟踪。相反,您可以使用带有IAsyncCollector<dynamic>
的输出绑定来更新文档。 Behind-the-scenes 我们将调用InsertOrReplaceDocumentAsync
,这将更新文档。
这是对我有用的完整示例:
代码:
#r "Microsoft.Azure.WebJobs.Extensions.DocumentDB"
#r "Newtonsoft.Json"
using System;
using Newtonsoft.Json.Linq;
public static async Task Run(string input, Binder binder, IAsyncCollector<dynamic> collector, TraceWriter log)
{
string deviceId = "0a3aa1ff-fc76-4bc9-9fe5-32871d5f451b";
dynamic document = await binder.BindAsync<JObject>(new DocumentDBAttribute("ItemDb", "ItemCollection")
{
ConnectionStringSetting = "brettsamfunc_DOCUMENTDB",
Id = deviceId
});
log.Info($"C# Event Hub trigger function processed a message: document: { document }");
document.value = 100;
document.child.value = 200;
await collector.AddAsync(document);
log.Info($"Updated document: { document }");
}
绑定:
{
"type": "documentDB",
"name": "collector",
"connection": "brettsamfunc_DOCUMENTDB",
"direction": "out",
"databaseName": "ItemDb",
"collectionName": "ItemCollection",
"createIfNotExists": false
}