Question

I'm currently running into problems while trying to customize the update script for a table of User Stories on Azure Mobile Services. My intention is to have the update script receive an item that contains an array of UserStory objects, construct a SQL string using that array, and then use mssql.query with that string against the UserStory table to update the individual records.

The following SQL achieves what I'm looking to do and works correctly when executed in Visual Studio:

UPDATE 
    masterstorylist.UserStory 
SET 
    UserStory.relativepriority = 
       CASE UserStory.id
          WHEN 'C36DC45B-170B-49F4-A747-6F4D989C1859' THEN '24'
          WHEN '7EC413C3-17A8-410A-A394-ABF334364226' THEN '25'
          WHEN '99890AFE-13C2-4E1A-8376-B501CB07080D' THEN '26'
       END

Here's the server script that I have created in an attempt to achieve the same result:

function update(item, user, request) {
if(item.stories.length > 0){
    var sql = "UPDATE masterstorylist.UserStory SET UserStory.relativepriority = CASE UserStory.id ";
    for(var i = 0; i < item.stories.length; ++i){
       sql+= ("WHEN '" + item.stories[i].id + "' THEN " + item.stories[i].relativepriority + " "); 
    }
    sql+="END";

   mssql.query(sql, {
      success: function(results) {
            request.respond();
      },
      error: function(err) {
            request.respond(err);
      }
   });
}
else{
    request.respond(statusCodes.NO_CONTENT, 'No records specified for update in request.');
}

}

The error I get back is

"sqlstate":"42S22","code:207"

which I think means that SQL can't find the relativepriority or id column. I've tried different syntax, such as qualifying the column names more or less or using [] around the columns, but the result is always the same.

I'm not sure what else to try, and details around creating and executing queries with the mssql object are hard to come by. I've been working off the examples here and here.

What am I missing?

EDIT: In case it helps, I reworked the code to see if using mssql.open would help. I modeled after the examples from the "MS Drivers for Node.js for SQL Server guide" (which I can't link to because I have low rep). The net result is the exact same error :/ Here's the new code in case it gives folks any ideas:

function update(item, user, request) {
if(item.stories.length > 0){
    var sql = "UPDATE UserStory SET relativepriority = CASE id ";
    for(var i = 0; i < item.stories.length; ++i){
       sql+= ("WHEN '" + item.stories[i].id + "' THEN " + item.stories[i].relativepriority + " "); 
    }
    sql+="END ";
   console.log("opening connection...");
   mssql.open({
       success: function(connection){
            console.log("mssql.open success");
            console.log("executing query..."); 
            connection.query(sql, function(err,results){
                if(err){
                     console.log("query failed");
                     request.respond(err)
                }
                console.log("query successful");
               request.respond();
           });
       },
       error: function(err) {
           console.log("fail on open: " + err);
           request.respond(err);
       }
   });

}
else{
    request.respond(statusCodes.OK, 'No records specified for update in request.');
}

}

P.S. This is my first post on Stack Overflow! :)

Was it helpful?

Solution

Ok, I figured out the answer to my own question. It turns out that the JSON object that the Mobile Service SDK was passing up wasn't formatted to the liking of Node.js. The item object coming into the script had an array of objects in it item.stories, which looked ok to me when it was logged to the console with console.log(item.stories); but apparently wasn't formatted well enough for me to access the individual objects in the 'item.stories' array using array notation.

I was able to fix both of the scripts above by adding the line var storiesToUpdate = JSON.parse(item.stories); and then using storiesToUpdate[i] instead of item.stories[i]. That seems to have done the trick. Ideally I'll find a way to fix the JSON generated on my clients so that I don't need this extra JSON.parse.

Here are three now working examples on how to update multiple records at once.

Simplest way to do what I wanted:

var storiesToUpdate;
var returnItem;
function update(item, user, request) {
    storiesToUpdate = JSON.parse(item.stories);
    returnItem = item;
    if(storiesToUpdate.length > 0){
       var sql = "UPDATE UserStory SET relativepriority = CASE id ";
       for(var i = 0; i < storiesToUpdate.length; ++i){
          sql+= ("WHEN '" + storiesToUpdate[i].id + "' THEN " + storiesToUpdate[i].relativepriority + " "); 
       }
       sql+="END ";
       mssql.query(sql,{
           success: function(connection){
               request.respond(statusCodes.OK, returnItem);
           },
           error: function(err) {
               console.log("fail on open: " + err);
               request.respond(err);
           }
       });
    }
    else{
        request.respond(statusCodes.OK, returnItem);
    }
}

Another way using mssql.open as well (not sure why you'd ever want to do this...):

var storiesToUpdate;
var returnItem;
function update(item, user, request) {
    storiesToUpdate = JSON.parse(item.stories);
    returnItem = item;
    if(storiesToUpdate.length > 0){
        var sql = "UPDATE UserStory SET relativepriority = CASE id ";
        for(var i = 0; i < storiesToUpdate.length; ++i){
           sql+= ("WHEN '" + storiesToUpdate[i].id + "' THEN " + storiesToUpdate[i].relativepriority + " "); 
        }
        sql+="END ";
       console.log("opening connection...");
       mssql.open({
           success: function(connection){
                console.log("mssql.open success");
                console.log("executing query..."); 
                connection.query(sql, function(err,results){
                    if(err){
                         console.log("query failed");
                         request.respond(err)
                    }
                    console.log("query successful");
                   request.respond(statusCodes.OK, returnItem);
                    //request.respond(statusCodes.OK); 
               });
           },
           error: function(err) {
               console.log("fail on open: " + err);
               request.respond(err);
           }
       });

    }
    else{
        request.respond(statusCodes.OK, returnItem);
    }
}

And lastly, here's how to update multiple records without using mssql using the recommended batching techniques (this is rough and probably needs to be cleaned up):

var UserStoryTable = tables.getTable('UserStory');
var batchSize = 10;
var startIndex = 0;
var endIndex = 0;
var totalCount = 0;
var errorCount = 0;
var g_item;
var g_request;
var storiesToUpdate;

function update(item, user, request) {
    //the json array has to be parsed first
    storiesToUpdate = JSON.parse(item.stories);
    g_item = item;
    g_request = request;
    if(item.stories.length > 0){
       updateItems();
    }
    else{
        console.log("empy update request");
        request.respond(statusCodes.OK);
    }
}

function updateItems(){
    var batchCompletedCount = 0; 

    var updateComplete = function() { 
        batchCompletedCount++; 
        totalCount++; 
        if(batchCompletedCount === batchSize || totalCount === storiesToUpdate.length) {                        
            if(totalCount < storiesToUpdate.length) {
                // kick off the next batch 
                updateItems(); 
            } else { 
                // or we are done, report the status of the job 
                // to the log and don't do any more processing 
                console.log("Update complete. %d Records processed. There were %d errors.", totalCount, errorCount); 
                g_request.respond(statusCodes.OK);
            } 
        } 
    };

    var errorHandler = function(err) { 
        errorCount++; 
        console.warn("Ignoring insert failure as part of batch.", err); 
        updateComplete(); 
    };

    var startIndex = totalCount;
    var endIndex = totalCount + batchSize - 1;
    if(endIndex >= storiesToUpdate.length) endIndex = storiesToUpdate.length - 1;

    for(var i = startIndex; i <= endIndex; i++) { 
        console.log("Updating: " + storiesToUpdate[totalCount]);
        UserStoryTable.update(storiesToUpdate[i],{ 
            success: updateComplete, 
            error: errorHandler 
        }); 
    }   
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top