Azure / azure-cosmosdb-js-server

The JavaScript SDK for server-side programming in Azure Cosmos DB
MIT License
178 stars 153 forks source link

_ts is not returned by upsertDocument or replaceDocument #33

Open graham-sportsmgmt opened 6 years ago

graham-sportsmgmt commented 6 years ago

I have written a Stored Procedure to do a partial Document update and I want to return only the _ts attribute in order for subsequent queries to use this as a parameter.

This was tested in the Azure Portal Data Explorer and using the node.js sdk, both had the same result.

Whether I use upsertDocument or replaceDocument these are the only four system attributes returned in the RequestCallback.resource:

"_rid": "0eUiAJMAdQDl9QAAAAAAAA==",
"_self": "dbs/0eUiAA==/colls/0eUiAJMAdQA=/docs/0eUiAJMAdQDl9QAAAAAAAA==/",
"_etag": "\"27014d93-0000-0000-0000-5b7ba4ae0000\"",
"_attachments": "attachments/"

The Document itself is updated properly by the Stored Procedure, and the changes (including the new _ts) can be verified immediately in Data Explorer.

I also tried executing a small query after the upsert/replace and even this doesn't work inside the same Stored Procedure:

SELECT c._ts FROM c WHERE c.id='f21d829d-2de5-0a27-8886-ff2c3ddb2119'

Return value from Stored Procedure:

[
    {}
]

Result in Data Explorer (run as SQL Query):

[
    {
        "_ts": 1534831246
    }
]

Stored Procedure code:

function UpdatePartial(id, update, rootNode){

    var context = getContext();
    var collection = context.getCollection();

    var query = `SELECT * FROM c WHERE c.id='${id}'`;

    var queryAccepted = collection.queryDocuments(collection.getSelfLink(), query, {}, onQueryResponse);
    if(!queryAccepted) throw "Unable to query DocumentDB";

    function onQueryResponse(err, documents, responseOptions) {

        if(err){
            throw err;
        }

        if(documents.length === 0){
            throw `Could not find document with id [${id}]`;
        }

        var source = documents[0];
        update = JSON.parse(update);

        if(rootNode){
            source[rootNode] = Merge(source[rootNode], update);
        } else {
            source = Merge(source, update);
        }

        var updateAccepted = collection.replaceDocument(source._self, source, onUpdateResponse);
        if(!updateAccepted) throw "Unable to update DocumentDB";

    }

    function onUpdateResponse(err, resource, options){

        if(err){
            throw err;
        }

        context.getResponse().setBody({"_ts": resource._ts || ''});

        // use this to return the entire document instead
        // context.getResponse().setBody(resource);

        // uncomment these lines to execute the query
        // var query = `SELECT c._ts FROM c WHERE c.id='${id}'`;
        // console.log(query);
        // collection.queryDocuments(collection.getSelfLink(), query, onTimeStampResponse);

    }

    function onTimeStampResponse(err, resource){

        if(err){
            throw err;
        }

        context.getResponse().setBody(resource);      

    }

    function Merge(source, update) {

        for (var key in update) {

            try {

                if ( update[key].constructor==Object ) {
                    source[key] = Merge(source[key], update[key]);
                } else {
                    source[key] = update[key];
                }

            } catch(err) {
                source[key] = update[key];
            }

        }

        return source;

    }

}

Here is the node.js code that calls the Stored Procedure:

exports.executeSproc = function(id, update, callback){

  let url = getCollectionUrl(config.database, config.collection) + '/sprocs/' + 'UpdatePartial';
  let options = [id, update];

  client.executeStoredProcedure(url, options, function(err, resource){

    if(err){
      console.error(`ERROR in documentdb.executeSproc\nid was:${id}\nUpdate was: ${JSON.stringify(update)}\nError:\n${JSON.stringify(err,null,2)}`);
      callback(err);
      return;
    }

    callback(resource);

  });

}
roopeshwar commented 6 years ago

+1 Facing the same issue

muwaqar commented 6 years ago

We are facing the same issue as well.

yulang-wang commented 5 years ago

+1. This issue also appear in createDocument

image

drago-draganov commented 5 years ago

+1

davidhjones commented 5 years ago

+1

nganbread commented 2 years ago

+1

dolenox commented 2 years ago

+1

koltachev commented 2 years ago

_ts is not assigned until end of transaction and that is after script code is finished, this means that while script (sproc) is running _ts is not yet available for documents change by current script transaction. For script transactions, same _ts (and same LSN) will be assigned to all docs updated as part of the transaction.

I guess that doesn't help much, as you would still need to obtain the _ts of a doc updated within script. Using JS ways like new Date object is one way though in some cases it may differ from actual one in updated docs. Anyhow, from within script it's not possible to retrieve transaction _ts. On client side that would be possible but I don't think there is a header for that. Nevertheless will look into adding one.

drago-draganov commented 2 years ago

It's great indeed to see a response 3 years later.