2

I have a block of code in javascript that takes in an array of items from an API (the source of truth for this data) and it is supposed to update the data in my dynamo database when the update date on each object in the array does not match what I have. Everything looks right to me but I'm always returning that nothing needs to be updated even when I've validated updates exist. Not quite sure what I'm doing wrong here.

let count = 0;

    for (let appToCompare of arrayOfFormattedApps) {

        let hasMatch = false;

        for (let index = 1; index < currentCachedListOfApps.length; ++index) {
            var cachedApp = currentCachedListOfApps[index];

            if (cachedApp.ApplicationId === appToCompare.ApplicationId) {
                if (cachedApp.LastUpdateDateTime !== appToCompare.LastUpdateDateTime) {
                    arrayOfAppsWithUpdates.push(appToCompare);
                    hasMatch = true;
                    console.log(cachedApp.AppName + ' is being updated')
                    ++count;
                    break;
                }
            }
        }

        if (hasMatch) {
            arrayOfAppsWithUpdates.push(appToCompare);
        }
    }
Funkel
  • 133
  • 1
  • 6
  • 21
  • Are you sure that the `ApplicationId`s are staying the same? – rassar Oct 28 '19 at 12:27
  • 1
    This isn't an answer to your question, but you are doing this twice: `arrayOfAppsWithUpdates.push(appToCompare);` – Jen R Oct 28 '19 at 12:35
  • With very little info on what's in the objects, it will be very difficult for us to help. Have you tried debugging the code with [debugger](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems)? – Sagar Chilukuri Oct 28 '19 at 12:37
  • Can be your problem the `++index` of your for? Can you change it for `index++` ? – Schwarz54 Oct 28 '19 at 12:39
  • 1
    @JonathanLarouche, `break` would only break inner for loop. So, `push` is still getting executed twice. – Sagar Chilukuri Oct 28 '19 at 12:39
  • Is there really a difference in this case between ++index and index++? I'll try it if there is @Schwarz54 – Funkel Oct 28 '19 at 13:08
  • @SagarChilukuri When i use a debugger i found no issue. because of the way this runs though i can only debug with the data i pass in through a unit test. The actual execution occurs on an aws lambda. I was concerned about the loop it runs in not running async but i'm not quite sure. it executes the rest of the code after the loop. – Funkel Oct 28 '19 at 13:09
  • @ExceptionalNullPointer I can make it start with 0 but i know for a fact there will only be a few instances where index 0 is the app that will match. potentially a bug though! ApplicationId's never change, this i know. – Funkel Oct 28 '19 at 13:10
  • @rassar I am very sure that applicationId is staying the same. I am also very sure that the LastUpdateDate that i'm checking is changing. – Funkel Oct 28 '19 at 13:17
  • @SagarChilukuri The rest of the data in the object is confidential. Assume the object only contains an ID, an Update date and a Name that i'm updating. the rest of the data is not pertinent to the fact that its not updating. – Funkel Oct 28 '19 at 13:17
  • @Funkel in this case no (I think) I was wrong sry, but yes are differents between i++ and ++i deppend of the situation you use https://stackoverflow.com/questions/24853/c-what-is-the-difference-between-i-and-i – Schwarz54 Oct 28 '19 at 13:25
  • @Schwarz54 Good to know there are differences. Thanks. – Funkel Oct 28 '19 at 13:29
  • 1
    So, are you sure you are actually not comparing the same references? Please write a [mcve] (we really don't need your sensitive data, but the full workflow of how you get to this code block would be great). You could however verify if `cachedApp === appToCompare` which would at least give an idea what is wrong here – Icepickle Oct 29 '19 at 16:06

6 Answers6

5

There are one issue in your code, array index start to from zero, but you loop start from 1

let index = 1

So if the first app updated, the code will can not detect it. Base on your code, I edited the index to zero and tried to create some dump data, and tried to run your code. Seem work well

const currentCachedListOfApps = [
    {
        ApplicationId: 1,
        AppName: "App 1",
        LastUpdateDateTime: 4
    },
    {
        ApplicationId: 2,
        AppName: "App 2",
        LastUpdateDateTime: 2
    }
];
const arrayOfFormattedApps = [
    {
        ApplicationId: 1,
        AppName: "App 1",
        LastUpdateDateTime: 1
    },
    {
        ApplicationId: 2,
        AppName: "App 2",
        LastUpdateDateTime: 3
    }
];


const arrayOfAppsWithUpdates = [];
let count = 0;
for (let appToCompare of arrayOfFormattedApps) {

    let hasMatch = false;

    for (let index = 0; index < currentCachedListOfApps.length; ++index) {
        var cachedApp = currentCachedListOfApps[index];

        if (cachedApp.ApplicationId === appToCompare.ApplicationId) {
            if (cachedApp.LastUpdateDateTime !== appToCompare.LastUpdateDateTime) {
                arrayOfAppsWithUpdates.push(appToCompare);
                hasMatch = true;
                console.log(cachedApp.AppName + ' is being updated')
                ++count;
                break;
            }
        }
    }

    if (hasMatch) {
        arrayOfAppsWithUpdates.push(appToCompare);
    }
}
console.log(arrayOfAppsWithUpdates);

So the only issue here is you push the data to arrayOfAppsWithUpdates twice for every updated app. So just please double check again your API to make sure it correct.

And especially two properties ApplicationId and LastUpdateDateTime on every App information object, since you use === to compare them, === will compare both data type (Number, String...) and data value also, so make sure they a same data type as well

Hope this help

Vo Kim Nguyen
  • 1,613
  • 10
  • 14
  • Just for the fun of it, how about you make `arrayOfFormattedApps` a shallow clone of `currentCachedListOfApps` (ie: `currentCachedListOfApps.slice()` or `[...currentCachedListOfApps]`, and manually change 1 of the `LastUpdateDateTime` object. I think that would really recreate the problem the OP is having – Icepickle Oct 29 '19 at 16:10
  • Not that case, I think. @Funkel said that he got the new data from an API. – Vo Kim Nguyen Oct 29 '19 at 17:03
2

it does indeed look right, so perhaps there is something outside of this codeblock that is wrong. One way to perhaps find the error would be to log out hte properties you compare.

...
    console.log(cachedApp.ApplicationId +" === "+ appToCompare.ApplicationId)
if (cachedApp.ApplicationId === appToCompare.ApplicationId) {
    console.log(cachedApp.LastUpdateDateTime +" !== "+ appToCompare.LastUpdateDateTime)
    if (cachedApp.LastUpdateDateTime !== appToCompare.LastUpdateDateTime) {
Joachim Haglund
  • 775
  • 5
  • 15
  • I would add some extra characters when logging to make it easier to see things like spaces, since those are problematic when comparing strings... `console.log("|" + cachedApp.ApplicationId +"| === |"+ appToCompare.ApplicationId + "|")` – Jen R Oct 28 '19 at 12:42
  • I can add comments but i can't log the entirety of the applications because they contain sensitive data. I can only log to screen with data passed in while running a unit test which seems to run correctly and update apps as expected. – Funkel Oct 28 '19 at 13:12
2

I would do something like the below, though I dont see something wrong, just a little clunky code:

let appsToUpdate = arrayOfFormattedApps.find((appToCompare, index)=> {
    for(let cachedApp in currentCachedListOfApps) {
        if(cachedApp.ApplicationId === appToCompare.ApplicationId) {
            if (cachedApp.LastUpdateDateTime !== appToCompare.LastUpdateDateTime) {
                return appToCompare
            }
        }
    }
})
// Do work on appsToUpdate
LostJon
  • 2,287
  • 11
  • 20
0

The code you have shared looks perfectly fine. However, I guess the reason this has happened is probably because you do a shallow clone at some place or another in your code.

Probably the easiest way to explain it would be to do it with some pseudo coding:

const arrayOfFormattedApps = [{
    ApplicationId: 1,
    AppName: "App 1",
    LastUpdateDateTime: 1
  }, {
    ApplicationId: 2,
    AppName: "App 2",
    LastUpdateDateTime: 3
  }];
// shallow clone, apps are the same references
const currentCachedListOfApps = [...arrayOfFormattedApps];
// deep clone
const deepClonedCache = JSON.parse(JSON.stringify( arrayOfFormattedApps ) );

// update original (will also update the shallow clone element)
arrayOfFormattedApps[0].LastUpdateDateTime = 5;

// reduced version of your for loops
function getAppsToUpdate( source, cache ) {
  return source.map( app => cache.filter( 
    cached => cached.ApplicationId === app.ApplicationId && cached.LastUpdateDateTime !== app.LastUpdateDateTime ) 
  ).flat();
}

// checks different arrays but with same references on it
console.log( getAppsToUpdate( arrayOfFormattedApps, currentCachedListOfApps ) );
// checks the deepclone that now is actually different
console.log( getAppsToUpdate( arrayOfFormattedApps, deepClonedCache ) );

This would be now the most obvious thing you could have, but say you have somewhere a code where you build up your current cache, then you would probably have something like:

function createAppCache( apps, currentCache = [] ) {
  return currentCache.concat( apps.filter( app => !currentCache.some( cache => cache.ApplicationId === cache.ApplicationId ) ) );
}

And then use that to initially set up your cache:

const currentCachedListOfApps = createAppCache( arrayOfFormattedApps );

This would give you the same problem again, the reference of the single items would match the references in your original arrayOfFormattedApps.

Icepickle
  • 12,689
  • 3
  • 34
  • 48
0

It may be that the equality check === is not passing if the data types are different. For example if the ApplicationId is a number in the array coming from API but it's a string in the array stored in dynamo.

In this case the fix would be to check equality with ==, which will coerce the types to match, like

if (cachedApp.ApplicationId == appToCompare.ApplicationId)

or you can cast both ids to string

if (cachedApp.ApplicationId.toString() === appToCompare.ApplicationId.toString())

If this doesn't fix it, I recommend you share any example on codepen or so with minimal data to reporoduce the issue. If you don't want to expose the data you can share the arrays with just ApplicationId and LastUpdateDateTime properties.

gafi
  • 12,113
  • 2
  • 30
  • 32
0

Here's a cleanup of your code, as a quick note, remember to clear your arrayOfAppsWithUpdates before going in, otherwise you might end up with duplicates and unnecessary multiple updates.

    for (let appToCompare of arrayOfFormattedApps) {

        for (let index = 0; index < currentCachedListOfApps.length; ++index) {
            var cachedApp = currentCachedListOfApps[index];

            if (cachedApp.ApplicationId == appToCompare.ApplicationId) {
                if (cachedApp.LastUpdateDateTime != appToCompare.LastUpdateDateTime) {
                    arrayOfAppsWithUpdates.push(appToCompare);
                    console.log(cachedApp.AppName + ' is being updated')
                    break;
                }
            }
        }
    }

The changes are:

  1. Removed let count = 0; because you can get it from the length of the arrayOfAppsWithUpdates array.

  2. Removed let hasMatch = false because you don't need it for your loops.

  3. Changed let index = 1 to let index = 0 in the inner loop because otherwise you would be skipping the first app.

  4. The === and !== are strict comparison operators, they match value and type. Changed them to == and != respectively so that they only compare values.

  5. Removed the snippet: if (hasMatch) { arrayOfAppsWithUpdates.push(appToCompare); } } because it was causing double insert of the appToCompare into the arrayOfAppsWithUpdates array.

This code block is tested and works as intended. If you still have ill-behavior after using it, then the problem must be somewhere else in your code.

Specifically, be careful how you get your arrayOfFormattedApps and currentCachedListOfApps arrays.

Javier Silva Ortíz
  • 2,864
  • 1
  • 12
  • 21