Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Azure Cosmos DB bietet sprachintegrierte, transaktionsbasierte Ausführung von JavaScript, mit der Sie gespeicherte Prozeduren, Trigger und benutzerdefinierte Funktionen (UDFs) schreiben können. Wenn Sie die API für NoSQL in Azure Cosmos DB verwenden, können Sie die gespeicherten Prozeduren, Trigger und UDFs mit JavaScript definieren. Sie können Ihre Logik in JavaScript schreiben und innerhalb des Datenbankmoduls ausführen. Sie können Trigger, gespeicherte Prozeduren und UDFs mithilfe des Azure-Portals, der JavaScript-Abfrage-API in Azure Cosmos DB und der Azure Cosmos DB für NoSQL-SDKs erstellen und ausführen.
Um eine gespeicherte Prozedur, einen Trigger oder eine UDF aufzurufen, müssen Sie sie registrieren. Weitere Informationen finden Sie unter Registrieren und Verwenden von gespeicherten Prozeduren, Triggern und benutzerdefinierten Funktionen.
Hinweis
Bei partitionierten Containern muss beim Ausführen einer gespeicherten Prozedur ein Partitionsschlüsselwert in den Anforderungsoptionen bereitgestellt werden. Gespeicherte Prozeduren sind immer auf einen Partitionsschlüssel bezogen. Elemente mit einem anderen Partitionsschlüsselwert sind für die gespeicherte Prozedur nicht sichtbar. Dies gilt auch für Trigger.
Hinweis
Serverseitige JavaScript-Features, einschließlich gespeicherter Prozeduren, Trigger und UDFs, unterstützen das Importieren von Modulen nicht.
Tipp
Azure Cosmos DB unterstützt die Bereitstellung von Containern mit gespeicherten Prozeduren, Triggern und UDFs. Weitere Informationen finden Sie unter Erstellen eines Azure Cosmos DB-Containers mit serverseitiger Funktionalität.
Wie man gespeicherte Prozeduren schreibt
Gespeicherte Prozeduren werden mit JavaScript geschrieben, und sie können Elemente in einem Azure Cosmos DB-Container erstellen, aktualisieren, lesen, abfragen und löschen. Gespeicherte Prozeduren werden pro Sammlung registriert und können für jedes Dokument oder eine Anlage verwendet werden, die in dieser Auflistung vorhanden ist.
Hinweis
Azure Cosmos DB verfügt über eine andere Laderichtlinie für gespeicherte Prozeduren. Da gespeicherte Prozeduren Code ausführen und eine beliebige Anzahl von Anforderungseinheiten (RUs) verwenden können, erfordert jede Ausführung eine Vorbelastung. Dadurch wird sichergestellt, dass gespeicherte Prozedurskripts keine Auswirkungen auf Back-End-Dienste haben. Der Betrag, der vorab berechnet wird, entspricht der durchschnittlichen Gebühr, die vom Skript in vorherigen Aufrufen verbraucht wird. Die durchschnittlichen RUs pro Vorgang werden vor der Ausführung reserviert. Wenn die Aufrufe in RUs viel Varianz aufweisen, kann die Budgetauslastung beeinträchtigt werden. Alternativ sollten Sie Batch- oder Massenanforderungen anstelle von gespeicherten Prozeduren verwenden, um Abweichung bei RU-Gebühren zu vermeiden.
Hier ist eine einfache gespeicherte Prozedur, die eine Antwort "Hello World" zurückgibt.
var helloWorldStoredProc = {
id: "helloWorld",
serverScript: function () {
var context = getContext();
var response = context.getResponse();
response.setBody("Hello, World");
}
}
Das Kontextobjekt bietet Zugriff auf alle Vorgänge, die in Azure Cosmos DB ausgeführt werden können, sowie Zugriff auf die Anforderungs- und Antwortobjekte. In diesem Fall verwenden Sie das Antwortobjekt, um den Textkörper der Antwort festzulegen, die an den Client zurückgesendet werden soll.
Nach dem Schreiben muss die gespeicherte Prozedur bei einer Sammlung registriert werden. Weitere Informationen finden Sie unter Verwendung gespeicherter Prozeduren in Azure Cosmos DB.
Erstellen von Elementen mithilfe gespeicherter Prozeduren
Wenn Sie ein Element mithilfe einer gespeicherten Prozedur erstellen, wird das Element in den Azure Cosmos DB-Container eingefügt und eine ID für das neu erstellte Element zurückgegeben. Das Erstellen eines Elements ist ein asynchroner Vorgang und hängt von den JavaScript-Rückruffunktionen ab. Die Rückruffunktion weist zwei Parameter auf: eines für das Fehlerobjekt, falls der Vorgang fehlschlägt, und ein anderer für einen Rückgabewert, in diesem Fall das erstellte Objekt. Innerhalb des Rückrufs können Sie entweder die Ausnahme behandeln oder einen Fehler auslösen. Wenn kein Rückruf bereitgestellt wird und ein Fehler auftritt, löst die Azure Cosmos DB-Laufzeit einen Fehler aus.
Die gespeicherte Prozedur enthält auch einen Parameter, um die Beschreibung als booleschen Wert festzulegen. Wenn der Parameter auf "true" festgelegt ist und die Beschreibung fehlt, löst die gespeicherte Prozedur eine Ausnahme aus. Andernfalls wird der Rest der gespeicherten Prozedur weiterhin ausgeführt.
Im folgenden Beispiel einer gespeicherten Prozedur wird ein Array neuer Azure Cosmos DB-Elemente als Eingabe verwendet, in den Azure Cosmos DB-Container eingefügt und die Anzahl der eingefügten Elemente zurückgegeben. In diesem Beispiel verwenden wir das ToDoList-Beispiel aus der Schnellstart-.NET-API für NoSQL.
function createToDoItems(items) {
var collection = getContext().getCollection();
var collectionLink = collection.getSelfLink();
var count = 0;
if (!items) throw new Error("The array is undefined or null.");
var numItems = items.length;
if (numItems == 0) {
getContext().getResponse().setBody(0);
return;
}
tryCreate(items[count], callback);
function tryCreate(item, callback) {
var options = { disableAutomaticIdGeneration: false };
var isAccepted = collection.createDocument(collectionLink, item, options, callback);
if (!isAccepted) getContext().getResponse().setBody(count);
}
function callback(err, item, options) {
if (err) throw err;
count++;
if (count >= numItems) {
getContext().getResponse().setBody(count);
} else {
tryCreate(items[count], callback);
}
}
}
Arrays als Eingabeparameter für gespeicherte Prozeduren
Wenn Sie eine gespeicherte Prozedur im Azure-Portal definieren, werden Eingabeparameter immer als Zeichenfolge an die gespeicherte Prozedur gesendet. Auch wenn Sie ein Array von Zeichenfolgen als Eingabe übergeben, wird das Array in eine Zeichenfolge konvertiert und an die gespeicherte Prozedur gesendet. Um dies zu umgehen, können Sie eine Funktion innerhalb Der gespeicherten Prozedur definieren, um die Zeichenfolge als Array zu analysieren. Der folgende Code zeigt, wie Sie einen Zeichenfolgeneingabeparameter als Array analysieren:
function sample(arr) {
if (typeof arr === "string") arr = JSON.parse(arr);
arr.forEach(function(a) {
// do something here
console.log(a);
});
}
Transaktionen in gespeicherten Prozeduren
Sie können Transaktionen für Elemente in einem Container mithilfe einer gespeicherten Prozedur implementieren. Im folgenden Beispiel werden Transaktionen in einer Fantasy-Fußball-Spiel-App verwendet, um Spieler zwischen zwei Teams in einem einzigen Vorgang zu handeln. Die gespeicherte Prozedur versucht, die beiden Azure Cosmos DB-Elemente zu lesen, die jeweils den Spieler-IDs entsprechen, die als Argument übergeben wurden. Wenn beide Spieler gefunden werden, aktualisiert die gespeicherte Prozedur die Elemente, indem sie ihre Teams austauschen. Wenn fehler auf dem Weg auftreten, löst die gespeicherte Prozedur eine JavaScript-Ausnahme aus, die die Transaktion implizit abbricht.
function tradePlayers(playerId1, playerId2) {
var context = getContext();
var container = context.getCollection();
var response = context.getResponse();
var player1Item, player2Item;
// query for players
var filterQuery =
{
'query' : 'SELECT * FROM Players p where p.id = @playerId1',
'parameters' : [{'name':'@playerId1', 'value':playerId1}]
};
var accept = container.queryDocuments(container.getSelfLink(), filterQuery, {},
function (err, items, responseOptions) {
if (err) throw new Error("Error" + err.message);
if (items.length != 1) throw "Unable to find player 1";
player1Item = items[0];
var filterQuery2 =
{
'query' : 'SELECT * FROM Players p where p.id = @playerId2',
'parameters' : [{'name':'@playerId2', 'value':playerId2}]
};
var accept2 = container.queryDocuments(container.getSelfLink(), filterQuery2, {},
function (err2, items2, responseOptions2) {
if (err2) throw new Error("Error " + err2.message);
if (items2.length != 1) throw "Unable to find player 2";
player2Item = items2[0];
swapTeams(player1Item, player2Item);
return;
});
if (!accept2) throw "Unable to read player details, abort ";
});
if (!accept) throw "Unable to read player details, abort ";
// swap the two players’ teams
function swapTeams(player1, player2) {
var player2NewTeam = player1.team;
player1.team = player2.team;
player2.team = player2NewTeam;
var accept = container.replaceDocument(player1._self, player1,
function (err, itemReplaced) {
if (err) throw "Unable to update player 1, abort ";
var accept2 = container.replaceDocument(player2._self, player2,
function (err2, itemReplaced2) {
if (err) throw "Unable to update player 2, abort"
});
if (!accept2) throw "Unable to update player 2, abort";
});
if (!accept) throw "Unable to update player 1, abort";
}
}
Gebundene Ausführung in gespeicherten Prozeduren
Das folgende Beispiel zeigt eine gespeicherte Prozedur, die Elemente in einen Azure Cosmos DB-Container massenimportiert. Die gespeicherte Prozedur behandelt die begrenzte Ausführung, indem der boolesche Rückgabewert von createDocument überprüft wird. Anschließend wird die Anzahl der Elemente verwendet, die in jedem Aufruf der gespeicherten Prozedur eingefügt wurden, um den Fortschritt über Batches hinweg nachzuverfolgen und fortzusetzen.
function bulkImport(items) {
var container = getContext().getCollection();
var containerLink = container.getSelfLink();
// The count of imported items, also used as the current item index.
var count = 0;
// Validate input.
if (!items) throw new Error("The array is undefined or null.");
var itemsLength = items.length;
if (itemsLength == 0) {
getContext().getResponse().setBody(0);
}
// Call the create API to create an item.
tryCreate(items[count], callback);
// Note that there are 2 exit conditions:
// 1) The createDocument request was not accepted.
// In this case the callback will not be called, we just call setBody and we are done.
// 2) The callback was called items.length times.
// In this case all items were created and we don’t need to call tryCreate anymore. Just call setBody and we are done.
function tryCreate(item, callback) {
var isAccepted = container.createDocument(containerLink, item, callback);
// If the request was accepted, the callback will be called.
// Otherwise report the current count back to the client,
// which will call the script again with the remaining set of items.
if (!isAccepted) getContext().getResponse().setBody(count);
}
// This is called when container.createDocument is done in order to process the result.
function callback(err, item, options) {
if (err) throw err;
// One more item has been inserted, increment the count.
count++;
if (count >= itemsLength) {
// If we created all items, we are done. Just set the response.
getContext().getResponse().setBody(count);
} else {
// Create the next document.
tryCreate(items[count], callback);
}
}
}
Asynchron/await mit gespeicherten Prozeduren
Das folgende Beispiel für eine gespeicherte Prozedur verwendet async/await mit "Promises" und einer Hilfsfunktion. Die gespeicherte Prozedur fragt nach einem Element ab und ersetzt es.
function async_sample() {
const ERROR_CODE = {
NotAccepted: 429
};
const asyncHelper = {
queryDocuments(sqlQuery, options) {
return new Promise((resolve, reject) => {
const isAccepted = __.queryDocuments(__.getSelfLink(), sqlQuery, options, (err, feed, options) => {
if (err) reject(err);
resolve({ feed, options });
});
if (!isAccepted) reject(new Error(ERROR_CODE.NotAccepted, "queryDocuments was not accepted."));
});
},
replaceDocument(doc) {
return new Promise((resolve, reject) => {
const isAccepted = __.replaceDocument(doc._self, doc, (err, result, options) => {
if (err) reject(err);
resolve({ result, options });
});
if (!isAccepted) reject(new Error(ERROR_CODE.NotAccepted, "replaceDocument was not accepted."));
});
}
};
async function main() {
let continuation;
do {
let { feed, options } = await asyncHelper.queryDocuments("SELECT * from c", { continuation });
for (let doc of feed) {
doc.newProp = 1;
await asyncHelper.replaceDocument(doc);
}
continuation = options.continuation;
} while (continuation);
}
main().catch(err => getContext().abort(err));
}
Anleitung zum Schreiben von Triggern
Azure Cosmos DB unterstützt Pre-Trigger und Posttrigger. Prä-Trigger werden vor dem Ändern eines Datenbankelements ausgeführt, und Post-Trigger werden nach dem Ändern eines Datenbankelements ausgeführt. Trigger werden nicht automatisch ausgeführt. Sie müssen für jeden Datenbankvorgang angegeben werden, in dem sie ausgeführt werden sollen. Nachdem Sie einen Trigger definiert haben, sollten Sie einen Vorabtrigger mithilfe der Azure Cosmos DB-SDKs registrieren und aufrufen.
Vorauslöser
Das folgende Beispiel zeigt, wie ein Vorabtrigger verwendet wird, um die Eigenschaften eines Azure Cosmos DB-Elements zu überprüfen, das erstellt wird. In diesem Beispiel wird das ToDoList-Beispiel aus der Schnellstart-.NET-API für NoSQL verwendet, um einem neu hinzugefügten Element eine Timestamp-Eigenschaft hinzuzufügen, wenn es kein Element enthält.
function validateToDoItemTimestamp() {
var context = getContext();
var request = context.getRequest();
// item to be created in the current operation
var itemToCreate = request.getBody();
// validate properties
if (!("timestamp" in itemToCreate)) {
var ts = new Date();
itemToCreate["timestamp"] = ts.getTime();
}
// update the item that will be created
request.setBody(itemToCreate);
}
Vortrigger können keine Eingabeparameter haben. Das Anforderungsobjekt im Trigger wird verwendet, um die dem Vorgang zugeordnete Anforderungsnachricht zu bearbeiten. Im vorherigen Beispiel wird der Vortrigger beim Erstellen eines Azure Cosmos DB-Elements ausgeführt, und der Anforderungstext enthält das Element, das im JSON-Format erstellt werden soll.
Wenn Trigger registriert sind, können Sie die Vorgänge angeben, mit denen sie ausgeführt werden können. Dieser Trigger sollte mit einem TriggerOperation Wert von TriggerOperation.Createerstellt werden, was bedeutet, dass die Verwendung des Triggers in einem Ersetzungsvorgang nicht zulässig ist.
Beispiele zum Registrieren und Aufrufen eines Vorabtriggers finden Sie unter "Pre-Trigger" und "Post-Trigger".
Posttrigger
Das folgende Beispiel zeigt einen Posttrigger. Dieser Trigger fragt das Metadatenelement ab und aktualisiert es mit Details zum neu erstellten Element.
function updateMetadata() {
var context = getContext();
var container = context.getCollection();
var response = context.getResponse();
// item that was created
var createdItem = response.getBody();
// query for metadata document
var filterQuery = 'SELECT * FROM root r WHERE r.id = "_metadata"';
var accept = container.queryDocuments(container.getSelfLink(), filterQuery,
updateMetadataCallback);
if(!accept) throw "Unable to update metadata, abort";
function updateMetadataCallback(err, items, responseOptions) {
if(err) throw new Error("Error" + err.message);
if(items.length != 1) throw 'Unable to find metadata document';
var metadataItem = items[0];
// update metadata
metadataItem.createdItems += 1;
metadataItem.createdNames += " " + createdItem.id;
var accept = container.replaceDocument(metadataItem._self,
metadataItem, function(err, itemReplaced) {
if(err) throw "Unable to update metadata, abort";
});
if(!accept) throw "Unable to update metadata, abort";
return;
}
}
Wichtig zu beachten ist die transaktionsale Ausführung von Triggern in Azure Cosmos DB. Der Posttrigger wird als Teil derselben Transaktion für das zugrunde liegende Element selbst ausgeführt. Eine Ausnahme während der Ausführung nach dem Trigger führt zum Scheitern der gesamten Transaktion. Alles, was committet wurde, wird rückgängig gemacht, und eine Ausnahme wird zurückgegeben.
Beispiele zum Registrieren und Aufrufen eines Vorabtriggers finden Sie unter "Pre-Trigger" und "Post-Trigger".
Wie man benutzerdefinierte Funktionen schreibt
Im folgenden Beispiel wird ein UDF zum Berechnen der Einkommensteuer für verschiedene Einkommensklassen erstellt. Diese UDF würde dann innerhalb einer Abfrage verwendet. Gehen Sie für die Zwecke dieses Beispiels davon aus, dass es einen Container namens "Einkommen" mit Eigenschaften wie folgt gibt:
{
"name": "Daniel Elfyn",
"country": "USA",
"income": 70000
}
Die folgende Funktionsdefinition berechnet die Einkommensteuer für verschiedene Einkommensstufen.
function tax(income) {
if (income == undefined)
throw 'no input';
if (income < 1000)
return income * 0.1;
else if (income < 10000)
return income * 0.2;
else
return income * 0.4;
}
Beispiele zum Registrieren und Verwenden einer UDF finden Sie unter Verwenden von benutzerdefinierten Funktionen.
Protokollierung
Wenn Sie gespeicherte Prozeduren, Trigger oder UDFs verwenden, können Sie die Schritte protokollieren, indem Sie die Skriptprotokollierung aktivieren. Eine Zeichenfolge für das Debuggen wird generiert, wenn EnableScriptLogging sie auf "true" festgelegt ist, wie in den folgenden Beispielen gezeigt:
let requestOptions = { enableScriptLogging: true };
const { resource: result, headers: responseHeaders} = await container.scripts
.storedProcedure(Sproc.id)
.execute(undefined, [], requestOptions);
console.log(responseHeaders[Constants.HttpHeaders.ScriptLogResults]);
Nächste Schritte
- Registrieren und Verwenden von gespeicherten Prozeduren, Triggern und UDFs in Azure Cosmos DB
- So schreiben Sie gespeicherte Prozeduren und Trigger mithilfe der JavaScript-Abfrage-API in Azure Cosmos DB
- Gespeicherte Prozeduren, Trigger und benutzerdefinierte Funktionen
- JavaScript-Abfrage-API in Azure Cosmos DB