I'm working on a project which will post periodic XML updates for users. I'm attempting to suppress information which hasn't changed since the last update.
Within node.js, I have assembled a user object which will be used to generate the XML:
users =
# actual application has 25 properties per user
[
{
USERID: 150927,
EMAIL: 'irving.block@email.net',
FIRSTNAME: 'Irving',
LASTNAME: 'Block',
COLOR: 'Green'
},
{
USERID: 1246007,
EMAIL: 'allen.adler@email.net',
FIRSTNAME: 'Adler',
LASTNAME: 'Allen',
COLOR: 'Blue'
},
{
CLKEY: 1248350,
EMAIL: 'walter.pidgeon@email.net',
FIRSTNAME: 'Walter',
LASTNAME: 'Pidgeon',
COLOR: 'Red'
}
]
I also have an object loaded which helps map user data to the eventual XML fields:
xml_map =
[
{
ID: 1,
ELEMENT: 'xml_map_assigned_id',
MAPPPED: 'USERID'
},
{
ID: 2,
ELEMENT: 'xml_map_email_address',
MAPPPED: 'EMAIL'
},
{
ID: 3,
ELEMENT: 'xml_map_user_firstname',
MAPPPED: 'FIRSTNAME'
},
{
ID: 4,
ELEMENT: 'xml_map_user_lastname',
MAPPPED: 'LASTNAME'
},
{
ID: 5,
ELEMENT: 'xml_map_user_color',
MAPPED: 'COLOR'
}
]
Using these objects, I need to compare with the last update, and remove matching properties (since I only want to post updates for data that has changed). Here's an example of what the last update (stored in the DB) might look like:
# nothing like this is used in the real application
# just showing here to give an idea of what the DB could look like
db_data =
[
{
USERID: 150927,
EMAIL: 'irving.block@email.net',
FIRSTNAME: 'IRVING',
LASTNAME: 'Block',
COLOR: 'Orange'
},
{
USERID: 1246007,
EMAIL: 'new.email@somewhere.com',
FIRSTNAME: 'Adler',
LASTNAME: 'Allen',
COLOR: 'Blue'
},
{
USERID: 1248350,
EMAIL: 'walter.pidgeon@email.net',
FIRSTNAME: 'Walt',
LASTNAME: 'Pidgeon',
COLOR: 'Red'
}
]
Using these examples, I'd like to end up with a User object like this (since only 1 thing has changed for each user):
users_final =
[
{
USERID: 150927,
COLOR: 'Orange'
},
{
USERID: 1246007,
EMAIL: 'new.email@somewhere.com',
},
{
USERID: 1248350,
FIRSTNAME: 'Walt',
}
]
And now for the pseudo-code that shows how I've been trying to accomplish this:
async = require "async"
handleChanges = (users, map, callback) ->
sql1 = "select..."
sql2 = "update..."
sql3 = "insert..."
db.query sql1, [], (err, rows, def) ->
if err? then console.log err
if rows[0]
if rows[0].ELEMENT_VALUE.toString() is users[map.MAPPED].toString()
# nothing has changed since last update
db.query sql2, ['Old'], (err, rows, def) ->
if err? then console.log err
callback null, map.MAPPED
else # this value has changed since the last update. Run update query
db.query sql2, ['New'], (err, rows, def) ->
if err? then console.log err
callback null, null
else # no value has ever been saved for this combo. Run insert query
db.query sql3, [], (err, rows, def) ->
if err? then console.log err
callback null, null
updateStore = (users, callback) ->
for map in xml_map
do(map) ->
handleChanges users, map, (err, del) ->
if del? then delete r[del]
callback null, r
async.map users, updateStore, (err, results) ->
console.log results
This obviously doesn't work right. I'm sure the updateStore function needs to be doing something different, but I'm at a loss.
Thanks in advance for your help!
I did similar thing in the project, but I use json instead of xml.
What I have done is retrieve a list of objects from db. and calculate a hash value for each of the object.
users =
[
{
USERID: 150927,
EMAIL: 'irving.block@email.net',
FIRSTNAME: 'Irving',
LASTNAME: 'Block',
COLOR: 'Green'
},
{
USERID: 1246007,
EMAIL: 'allen.adler@email.net',
FIRSTNAME: 'Adler',
LASTNAME: 'Allen',
COLOR: 'Blue'
}
]
hash = [
'c8addc875913a367486ba8343f68e349667e0334',
'df3d067e876437996237d0fde90466703ea303b9'
]
on the client side, I do compare the each old hash to the new hash. if different I use php.js or underscore.js. php.js can do array_diff to get differents between two object. Of course you can just do array_diff with comparing hash.
If your data structure is nested like this
{
User: {
FIRSTNAME: 'Irving',
LASTNAME: 'Block',
USERID: 150927
}
OtherInfo: {
EMAIL: 'irving.block@email.net'
}
}
you can flatten it to following before doing array_diff because array_diff only work on one level.
{
"User.FIRSTNAME": 'Irving',
"User.LASTNAME": 'Block',
"User.USERID": 150927,
"OtherInfo.EMAIL": 'irving.block@email.net'
}
I'm not sure if there is enough information about your expected XML output for me to help there, but the users_final
result you are looking for can be calculated with a fairly straight forward comparison algorithm. The core algorithm is:
difference = (a, b, idFieldName) ->
if a[idFieldName] != b[idFieldName]
throw new Error("#{idFieldName} values must match.")
diff = {}
diff[idFieldName] = a[idFieldName]
isDifferent = false
for key, value of b
if key != idFieldName and a[key].toUpperCase() != value.toUpperCase()
isDifferent = true
diff[key] = value
if isDifferent
return diff
else
return false
Here is a fully working example including using the input you provided... with one exception. I think you have a typo in your users
literal. I switched it from CLKEY
to USERID
so it matches the other rows. Just click on the "Run" button in the upper right hand corner after following the link to see your expected users_final
result.