Aracılığıyla paylaş


Azure Cosmos DB'de saklı yordamlar, tetikleyiciler ve kullanıcı tanımlı işlevler yazma

UYGULANANLAR: NoSQL

Azure Cosmos DB saklı yordamlar, tetikleyiciler ve kullanıcı tanımlı işlevler (UDF) yazmanıza olanak tanıyan dille tümleşik, işlemsel JavaScript yürütmesi sağlar. Azure Cosmos DB'de NoSQL api'sini kullandığınızda JavaScript kullanarak saklı yordamları, tetikleyicileri ve UDF'leri tanımlayabilirsiniz. JavaScript'te mantığınızı yazabilir ve veritabanı altyapısı içinde yürütebilirsiniz. Azure portalını, Azure Cosmos DB'deki JavaScript sorgu API'sini ve NoSQL SDK'ları için Azure Cosmos DB'yi kullanarak tetikleyiciler, saklı yordamlar ve UDF'ler oluşturabilir ve yürütebilirsiniz.

Saklı yordamı, tetikleyiciyi veya UDF'yi çağırmak için kaydetmeniz gerekir. Daha fazla bilgi için bkz . Azure Cosmos DB'de saklı yordamlar, tetikleyiciler ve kullanıcı tanımlı işlevlerle çalışma.

Not

Bölümlenmiş kapsayıcılar için, saklı yordam yürütülürken istek seçeneklerinde bir bölüm anahtarı değeri sağlanmalıdır. Saklı yordamların kapsamı her zaman bir bölüm anahtarı olarak belirlenmiştir. Farklı bir bölüm anahtarı değerine sahip öğeler saklı yordama görünmez. Bu, tetikleyiciler için de geçerlidir.

Not

Saklı yordamlar, tetikleyiciler ve UDF'ler dahil olmak üzere sunucu tarafı JavaScript özellikleri modülleri içeri aktarmayı desteklemez.

İpucu

Azure Cosmos DB saklı yordamlar, tetikleyiciler ve UDF'ler ile kapsayıcı dağıtmayı destekler. Daha fazla bilgi için bkz . Sunucu tarafı işlevselliğiyle Azure Cosmos DB kapsayıcısı oluşturma.

Saklı yordamları yazma

Saklı yordamlar JavaScript kullanılarak yazılır ve Azure Cosmos DB kapsayıcısı içindeki öğeleri oluşturabilir, güncelleştirebilir, okuyabilir, sorgulayabilir ve silebilir. Saklı yordamlar koleksiyon başına kaydedilir ve bu koleksiyonda bulunan herhangi bir belge veya ek üzerinde çalışabilir.

Not

Azure Cosmos DB,saklı yordamlar için farklı bir ücretlendirme ilkesine sahiptir. Saklı yordamlar kod yürütebileceğinden ve herhangi bir sayıda istek birimi (RU) tüketebildiğinden, her yürütme için ön ödeme gerekir. Bu, saklı yordam betiklerinin arka uç hizmetlerini etkilememesini sağlar. Peşin olarak ücretlendirilen tutar, önceki çağrılarda betik tarafından tüketilen ortalama ücrete eşittir. Yürütmeden önce işlem başına ortalama RU'lar ayrılır. Çağrıların RU'larda çok fazla varyansı varsa bütçe kullanımınız etkilenebilir. Alternatif olarak, RU ücretlerine göre varyansı önlemek için saklı yordamlar yerine toplu veya toplu istekler kullanmanız gerekir.

"Merhaba Dünya" yanıtı döndüren basit bir saklı yordam aşağıdadır.

var helloWorldStoredProc = {
    id: "helloWorld",
    serverScript: function () {
        var context = getContext();
        var response = context.getResponse();

        response.setBody("Hello, World");
    }
}

Bağlam nesnesi, Azure Cosmos DB'de gerçekleştirilebilecek tüm işlemlere ve istek ve yanıt nesnelerine erişim sağlar. Bu durumda, yanıtın gövdesini istemciye geri gönderilecek şekilde ayarlamak için yanıt nesnesini kullanırsınız.

Yazıldıktan sonra saklı yordamın bir koleksiyona kaydedilmesi gerekir. Daha fazla bilgi edinmek için bkz . Azure Cosmos DB'de saklı yordamları kullanma.

Saklı yordamları kullanarak öğe oluşturma

Saklı yordam kullanarak bir öğe oluşturduğunuzda, öğe Azure Cosmos DB kapsayıcısına eklenir ve yeni oluşturulan öğenin kimliği döndürülür. Öğe oluşturmak zaman uyumsuz bir işlemdir ve JavaScript geri çağırma işlevlerine bağlıdır. Geri çağırma işlevinin iki parametresi vardır: biri işlemin başarısız olması durumunda hata nesnesi için, diğeri ise döndürülen değer için, bu durumda oluşturulan nesne. Geri çağırmanın içinde özel durumu işleyebilir veya bir hata oluşturabilirsiniz. Geri çağırma sağlanmadıysa ve bir hata varsa Azure Cosmos DB çalışma zamanı bir hata oluşturur.

Saklı yordam ayrıca açıklamayı boole değeri olarak ayarlamak için bir parametre içerir. Parametresi true olarak ayarlandığında ve açıklama eksikse saklı yordam bir özel durum oluşturur. Aksi takdirde, saklı yordamın geri kalanı çalışmaya devam eder.

Aşağıdaki saklı yordam örneği, giriş olarak bir dizi yeni Azure Cosmos DB öğesi alır, bunu Azure Cosmos DB kapsayıcısına ekler ve eklenen öğelerin sayısını döndürür. Bu örnekte, NoSQL için Hızlı Başlangıç .NET API'sinden ToDoList örneğini kullanıyoruz.

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);
        }
    }
}

Saklı yordamlar için giriş parametresi olarak diziler

Azure portalında saklı yordam tanımladığınızda, giriş parametreleri her zaman saklı yordama bir dize olarak gönderilir. Dize dizisini giriş olarak geçirseniz bile, dizi bir dizeye dönüştürülür ve saklı yordama gönderilir. Bu sorunu geçici olarak çözmek için saklı yordamınızda dizeyi dizi olarak ayrıştıracak bir işlev tanımlayabilirsiniz. Aşağıdaki kod, bir dize giriş parametresinin dizi olarak nasıl ayrıştırılmış olduğunu gösterir:

function sample(arr) {
    if (typeof arr === "string") arr = JSON.parse(arr);

    arr.forEach(function(a) {
        // do something here
        console.log(a);
    });
}

Saklı yordamlar içindeki işlemler

Saklı yordam kullanarak kapsayıcı içindeki öğelere işlem uygulayabilirsiniz. Aşağıdaki örnek, tek bir operasyonda iki takım arasında oyuncu takası yapmak için fantezi futbol oyun uygulaması içindeki işlemleri kullanır. Saklı yordam, her biri bağımsız değişken olarak geçirilen oynatıcı kimliklerine karşılık gelen iki Azure Cosmos DB öğesini okumaya çalışır. Her iki oyuncu da bulunursa saklı yordam, takımlarını değiştirerek öğeleri güncelleştirir. Yol boyunca herhangi bir hatayla karşılaşılırsa saklı yordam işlemi örtük olarak durduran bir JavaScript özel durumu oluşturur.

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";
    }
}

Saklı yordamlar içinde sınırlanmış yürütme

Aşağıda, öğeleri bir Azure Cosmos DB kapsayıcısına toplu olarak içeri aktaran bir saklı yordam örneği verilmiştir. Saklı yordam, içinden boole dönüş değerini createDocumentdenetleyerek sınırlanmış yürütmeyi işler ve ardından toplu işlemler arasında ilerleme durumunu izlemek ve sürdürmek için saklı yordamın her çağrısına eklenen öğe sayısını kullanır.

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);
        }
    }
}

Saklı yordamlarla zaman uyumsuz/await

Aşağıdaki saklı yordam örneği, yardımcı işlevi kullanan Promises ile birlikte kullanırasync/await. Saklı yordam bir öğe için sorgular ve onu değiştirir.

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));
}

Tetikleyicileri yazma

Azure Cosmos DB, ön tetikleyicileri ve son tetikleyicileri destekler. Ön tetikleyiciler bir veritabanı öğesi değiştirilmeden önce yürütülür ve bir veritabanı öğesi değiştirildikten sonra son tetikleyiciler yürütülür. Tetikleyiciler otomatik olarak yürütülemez. Yürütmelerini istediğiniz her veritabanı işlemi için belirtilmelidir. Bir tetikleyici tanımladıktan sonra Azure Cosmos DB SDK'larını kullanarak bir ön tetikleyici kaydedip çağırmanız gerekir.

Ön tetikleyiciler

Aşağıdaki örnekte, oluşturulan Bir Azure Cosmos DB öğesinin özelliklerini doğrulamak için ön tetikleyicinin nasıl kullanıldığı gösterilmektedir. Bu örnekte NoSQL için Hızlı Başlangıç .NET API'sinden Alınan ToDoList örneği, yeni eklenen bir öğeye bir zaman damgası özelliği eklenmiyorsa kullanılır.

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);
}

Ön tetikleyicilerde herhangi bir giriş parametresi olamaz. Tetikleyicideki istek nesnesi, işlemle ilişkili istek iletisini işlemek için kullanılır. Önceki örnekte, bir Azure Cosmos DB öğesi oluşturulurken ön tetikleyici çalıştırılır ve istek iletisi gövdesi JSON biçiminde oluşturulacak öğeyi içerir.

Tetikleyiciler kaydedildiğinde, birlikte çalıştırabileceği işlemleri belirtebilirsiniz. Bu tetikleyici değeriyle TriggerOperation.Createoluşturulmalıdır. Başka bir TriggerOperation deyişle, tetikleyicinin değiştirme işleminde kullanılmasına izin verilmez.

Ön tetikleyici kaydetme ve çağırma örnekleri için bkz . ön tetikleyiciler ve son tetikleyiciler.

Son tetikleyiciler

Aşağıdaki örnekte bir son tetikleyici gösterilmektedir. Bu tetikleyici meta veri öğesi için sorgular ve yeni oluşturulan öğe hakkındaki ayrıntılarla güncelleştirir.

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;
    }
}

Dikkat edilmesi gereken önemli noktalardan biri, Azure Cosmos DB'de tetikleyicilerin işlemsel olarak yürütülmesidir. Tetikleyici sonrası, temel alınan öğenin kendisi için aynı işlemin bir parçası olarak çalışır. Tetikleyici sonrası yürütme sırasında oluşan bir özel durum tüm işlemi başarısız olur. İşlenen her şey geri alınır ve bir özel durum döndürülür.

Ön tetikleyici kaydetme ve çağırma örnekleri için bkz . ön tetikleyiciler ve son tetikleyiciler.

Kullanıcı tanımlı işlevler yazma

Aşağıdaki örnek, çeşitli gelir ayraçları için gelir vergisini hesaplamak için bir UDF oluşturur. Daha sonra bu kullanıcı tanımlı işlev bir sorgunun içinde kullanılır. Bu örneğin amaçları doğrultusunda, aşağıdaki özelliklere sahip Gelirler adlı bir kapsayıcı olduğunu varsayalım:

{
   "name": "Daniel Elfyn",
   "country": "USA",
   "income": 70000
}

Aşağıdaki işlev tanımı, çeşitli gelir ayraçları için gelir vergisini hesaplar:

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;
}

UDF'yi kaydetme ve kullanma örnekleri için bkz . Azure Cosmos DB'de kullanıcı tanımlı işlevlerle çalışma.

Günlük Kaydı

Saklı yordamları, tetikleyicileri veya UDF'leri kullanırken betik günlüğünü etkinleştirerek adımları günlüğe kaydedebilirsiniz. Aşağıdaki örneklerde gösterildiği gibi true olarak ayarlandığında hata ayıklama için bir dize oluşturulurEnableScriptLogging:

let requestOptions = { enableScriptLogging: true };
const { resource: result, headers: responseHeaders} = await container.scripts
      .storedProcedure(Sproc.id)
      .execute(undefined, [], requestOptions);
console.log(responseHeaders[Constants.HttpHeaders.ScriptLogResults]);

Sonraki adımlar

Azure Cosmos DB'de saklı yordamları, tetikleyicileri ve UDF'leri yazma veya kullanma hakkında daha fazla bilgi edinin: