Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DocumentDB call stored procedure from another stored procedure or itself

Is there a way to recursively call stored procedures (or even UDFs if that will work) against DocumentDB documents?

We have a document that looks something like this:

{
  "docID" : "my_id",
  "owner" : "fred",
  "items" : [
    {
      "itemID" : "1",
      "type" : "item",
      "value" : 3
    },
    {
      "itemID" : "2",
      "type" : "group",
      "items" : [
        {
          "itemID" : "2.1",
          "type" : "group",
          "items" : [
            {
              "itemID" : "2.1.1",
              "type" : "item",
              "value" : 2
            },
            {
              "itemID" : "2.1.2",
              "type" : "item",
              "value" : 4
            }
          ]
        },
        {
          "itemID" : "2.2",
          "type" : "item",
          "value" : 1
        }
      ]
    }
  ]
}

Any time we have "items", that "items" array can contain entries that are a mix of "type" : "item" and "type" : "group". Entries that are of "type" : "item" have a simple "value" field that needs to be summed. Entries that are of "type" : "group" have an "items" array... and so on. In theory, there is no limit to the level of recursion, which I acknowledge is a problem, but in practice, the levels will rarely get below 4 or 5 deep.

Pseudocode for what I'm trying to write looks something like this:

function sumValues(items) {
    int total = 0;
    forEach(item in items) {
        if (item.type == "item") {
            total += item.value;
        } else {
            total += sumValues(item.items);
        }
    }
    return total;
}

function sumAllValues() {
  var ctx = getContext();
  var coll = ctx.getCollection();
  var response = ctx.getResponse();

  // query for docs by owner
  var filterQuery = 'SELECT * FROM Docs d where d.owner = \\\"fred\\\"';
  var done = coll.queryDocuments(coll.getSelfLink(), filterQuery, {},
    function (err, docs, options) {
      if (err) throw new Error ('Error' + err.message);

      var total = 0;
      docs.forEach(function(doc) {
        total += sumTotals(doc.items);
      });

      response.setBody('Total: ' + total);
    });
}

Is this even possible? Does DocumentDB support calling a sproc from another sproc? Can a sproc call itself?

I have found a few DocumentDB stored procedure references online, including this and this and this and this plus a host of other pages.

If it's possible, I think I might have to somehow query the collection to get the sproc that I want to call, and then somehow reference the sproc, instead of just calling sumTotals() directly as you would with a standalone language.

We're just starting to look at programming with DocumentDB, so we're not completely sure what we can do with it yet. Thanks for any assistance or advice.

like image 677
shoover Avatar asked Mar 17 '15 19:03

shoover


1 Answers

I think you're on the right track here.

It is not possible to execute a stored procedure from within a stored procedure.

However, you can define JS functions inside a stored procedure, which can be can be referenced, called, and re-used from within that stored procedure.

In this case, simply define your sumValues() function inside the parent sumAllValues() stored procedure (just like the swapItems() example you mentioned).

function sumAllValues() {
    var ctx = getContext();
    var coll = ctx.getCollection();
    var response = ctx.getResponse();

    // query for docs by owner
    var filterQuery = 'SELECT * FROM Docs d where d.owner = \\\"fred\\\"';
    var done = coll.queryDocuments(coll.getSelfLink(), filterQuery, {},
        function (err, docs, options) {
            if (err) throw new Error ('Error' + err.message);

            var total = 0;
            docs.forEach(function(doc) {
                total += sumValues(doc.items);
            });

            response.setBody('Total: ' + total);
        });

    function sumValues(items) {
        int total = 0;
        items.forEach(function(item) {
            if (item.type == "item") {
                total += item.value;
            } else {
                total += sumValues(item.items);
            }
        });
        return total;
    }
}

You can also define UDFs for logic you'd like to share and re-use across multiple stored procedures and queries.

like image 125
Andrew Liu Avatar answered Oct 05 '22 22:10

Andrew Liu