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

UYGULANDıĞı YER: SQL API

Azure Cosmos DB saklı yordamlar, tetikleyiciler ve kullanıcı tanımlı işlevler (UFS) yazmanız için JavaScript'in dille tümleşik, işlemsel yürütülmesini sağlar. Azure SQL DB'de Cosmos API'sini kullanırken saklı yordamları, tetikleyicileri ve UFS'leri JavaScript dilinde tanımlayabilirsiniz. Mantığınızı JavaScript'te yazabilir ve veritabanı altyapısının içinde yürütebilirsiniz. Azure portal, Azure Cosmos DB'de JavaScript diliyle tümleşik sorgu API'si ve Cosmos DB SQL API istemci SDK'larını kullanarak tetikleyiciler, saklı yordamlar ve UFS'ler oluşturabilir ve yürütebilirsiniz.

Saklı yordam, tetikleyici ve kullanıcı tanımlı bir işlevi çağırmanız için bunu kaydetmelisiniz. Daha fazla bilgi için bkz. Azure Cosmos DB'de saklı yordamlar, tetikleyiciler, kullanıcı tanımlı işlevlerle çalışma.

Not

Bölümlenmiş kapsayıcılar için saklı yordam yürütürken istek seçeneklerinde bölüm anahtarı değeri sağlanmalıdır. Saklı yordamların kapsamı her zaman bir bölüm anahtarına göredir. Farklı bir bölüm anahtarı değerine sahip öğeler saklı yordamda görünmez. Bu, tetikleyicilere de uygulanır.

İpucu

Cosmos saklı yordamlar, tetikleyiciler ve kullanıcı tanımlı işlevlerle kapsayıcıları dağıtmayı destekler. Daha fazla bilgi için bkz. Sunucu tarafı Cosmos azure veritabanı kapsayıcısı oluşturma.

Saklı yordamlar yazma

Saklı yordamlar JavaScript kullanılarak yazılır; azure Cosmos kapsayıcısı içindeki öğeleri oluşturabilir, güncelleştirabilir, okuyabilir, sorgular ve silebilirler. Saklı yordamlar koleksiyon başına kaydedilir ve bu koleksiyonda mevcut olan herhangi bir belge veya ek üzerinde çalışabilir.

Burada bir "Merhaba Dünya" yanıtı döndüren basit bir saklı yordam ve ardından gelir.

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ştirilecek tüm işlemlere ve istek ve yanıt nesnelerine erişim sağlar. Bu durumda yanıt nesnesini kullanarak yanıtın gövdesini istemciye geri gönderilecek şekilde ayarlayabilirsiniz.

Yazılan saklı yordamın bir koleksiyona kayıtlı olması gerekir. Daha fazla bilgi için Azure Cosmos DB'de saklı yordamları kullanma makalesine bakın.

Saklı yordamı kullanarak öğe oluşturma

Saklı yordamı kullanarak bir öğe oluşturulduğunda, öğe Azure Cosmos kapsayıcıya 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şlem başarısız olursa hata nesnesi için, diğeri de dönüş değeri için; bu durumda, oluşturulan nesne. Geri çağırmanın içinde, özel durumu işebilir veya bir hata alabilirsiniz. Bir geri arama sağlanmazsa ve bir hata olursa, Azure Cosmos DB çalışma zamanı hata verir.

Saklı yordam ayrıca açıklamayı ayarlamak için bir parametre içerir. Bu bir boole değeridir. parametresi true olarak ayarlandığı ve açıklama eksik olduğu zaman saklı yordam bir özel durum oluşturur. Aksi takdirde saklı yordamın geri kalanı çalıştırmaya devam eder.

Aşağıdaki örnek saklı yordam giriş olarak yeni Azure Cosmos öğelerini alır, azure Cosmos kapsayıcıya ekler ve eklenen öğelerin sayısını döndürür. Bu örnekte Hızlı Başlangıç .NET SQL API'sinde ToDoList örneğinden SQL var

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

Bir saklı yordam Azure portal, giriş parametreleri her zaman saklı yordama bir dize olarak gönderilir. Bir dize dizisini giriş olarak geçse bile, dizi dizeye dönüştürülür ve saklı yordama gönderilir. Bunun üzerinde çalışmak için saklı yordamınız içinde dizeyi dizi olarak ayrıştırmak üzere bir işlev tanımlayabilirsiniz. Aşağıdaki kod, bir dize giriş parametresinin dizi olarak nasıl ayrıştırılır:

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 gerçekleştirebilirsiniz. Aşağıdaki örnek, iki takım arasındaki oyuncuları tek bir işlemde takas etmek için bir futbol futbolu oyun uygulamasındaki işlemleri kullanır. Saklı yordam, her biri bağımsız değişken olarak Cosmos oyuncu kimlikleri için karşılık gelen iki Azure azure sanal ağ öğelerini okumaya çalışır. İki oyuncu da bulunursa saklı yordam, takımlarını değiştirerek öğeleri günceller. Bu süre boyunca herhangi bir hatayla karşılaşırsanız saklı yordam, işlemi örtülü olarak durduran bir JavaScript özel durumu oluşturur.

// JavaScript source code
function tradePlayers(playerId1, playerId2) {
    var context = getContext();
    var container = context.getCollection();
    var response = context.getResponse();

    var player1Document, player2Document;

    // 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 both names";
            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 both names";
                    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 depolama kapsayıcısı içine toplu olarak içeri aktaran bir saklı yordam Cosmos ve ve bir örnektir. Saklı yordam, 'den boole dönüş değerini kontrol ederek sınırlanmış yürütmeyi işler ve ardından toplu işler arasında ilerlemeyi izlemek ve devam etmek için saklı yordamın her çağırmada eklenen öğe createDocument sayısını kullanır.

function bulkImport(items) {
    var container = getContext().getCollection();
    var containerLink = container.getSelfLink();

    // The count of imported items, also used as 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, callback will be called.
        // Otherwise report current count back to the client,
        // which will call the script again with 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 next document.
            tryCreate(items[count], callback);
        }
    }
}

Saklı yordamlarla Async await

Aşağıda, yardımcı işlev kullanan Promises ile async-await kullanan bir saklı yordam örneği ve bir örnek ve sağlanıyor. Saklı yordam bir öğeyi sorgular ve onun yerini 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. Bir veritabanı öğesi değiştirmeden önce ön tetikleyiciler yürütülür ve bir veritabanı öğesi değiştirdikten sonra son tetikleyiciler yürütülür. Tetikleyiciler otomatik olarak yürütülmez, yürütmelerini istediğiniz her veritabanı işlemi için belirtilmelidir. Tetikleyici tanımdikten sonra Azure Cosmos DB SDK'lerini kullanarak bir ön tetikleyiciyi kaydetmeniz ve çağırmanız gerekir.

Ön tetikleyiciler

Aşağıdaki örnekte, oluşturulan Bir Azure Cosmos öğesinin özelliklerini doğrulamak için bir ön tetikleyicinin nasıl kullanıldıkları gösterir. Bu örnekte, yeni eklenen bir öğeye bir zaman damgası özelliği eklemek için Hızlı Başlangıç .NET SQLAPI'sinde Bulunan ToDoList örneğinden yararlanarak yeni bir öğe içermemektedir.

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 tetikleyicilerin hiçbir giriş parametresi olamaz. Tetikleyicide istek nesnesi, işlemle ilişkili istek iletiyi işlemek için kullanılır. Önceki örnekte, azure Cosmos öğesi oluşturulurken ön tetikleyici çalıştırıldı ve istek iletisi gövdesi JSON biçiminde oluşturulacak öğeyi içeriyor.

Tetikleyiciler kaydedlendiğinde, birlikte çalıştıracak işlemleri belirtsiniz. Bu tetikleyici değeriyle oluşturularak, tetikleyicinin aşağıdaki kodda gösterildiği gibi değiştirme işlemi içinde TriggerOperation TriggerOperation.Create kullanımına izin verilmez.

Ön tetikleyici kaydetme ve çağırma örnekleri için ön tetikleyiciler ve tetikleyici sonrası makalelere bakın.

Son tetikleyiciler

Aşağıdaki örnekte, bir tetikleyici sonrası gösterir. Bu tetikleyici, meta veri öğesini sorgular ve yeni oluşturulan öğenin ayrıntılarıyla bunu günceller.

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 etmek gereken önemli bir şey, Azure Cosmos DB'de tetikleyicilerin işlemsel olarak yürütülmesidir. Tetikleyici sonrası, temel öğenin kendisi için aynı işlem kapsamında çalışır. Tetikleyici sonrası yürütme sırasında bir özel durum tüm işlem başarısız olur. Iş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 ön tetikleyiciler ve tetikleyici sonrası makalelere bakın.

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

Aşağıdaki örnek, çeşitli gelir ayraçları için gelir vergisini hesaplamak üzere bir UDF oluşturur. Bu kullanıcı tanımlı işlev daha sonra 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 varsayın:

{
   "name": "Satya Nadella",
   "country": "USA",
   "income": 70000
}

Aşağıda, çeşitli gelir ayraçları için gelir vergisini hesaplamak için kullanılan bir işlev tanımı yer almaktadır:

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

Kullanıcı tanımlı bir işlevi kaydetme ve kullanma örnekleri için Azure Cosmos DB'de kullanıcı tanımlı işlevleri kullanma makalesine bakın.

Günlüğe Kaydetme

Saklı yordam, tetikleyiciler veya kullanıcı tanımlı işlevler kullanırken betik günlüğünü etkinleştirerek adımları günlüğe atabilirsiniz. Hata ayıklama dizesi, aşağıdaki örneklerde EnableScriptLogging gösterildiği gibi true olarak ayarlanırken oluşturulur:

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

Daha fazla bilgi edinin ve Azure Cosmos DB'de saklı yordamlar, tetikleyiciler ve kullanıcı tanımlı işlevler yazma veya kullanma: