Finding an index in an array of objects with 3 possible outcomes currentUserPosts will have a post object with an id that either matches a tempId, an Id, or nothing.

If there's a tempId match there won't be an id match and vice versa.

This code works but there's something about it I don't like. How can it be refactored?

let postIndex;
postIndex = currentUserPosts.findIndex(post =&gt; post.id === upsertParams.tempId);
if (postIndex === -1) {
  postIndex = currentUserPosts.findIndex(post =&gt; post.id === upsertParams.id);
}
if (postIndex === -1) {
  currentUserPosts.push(upsertParams);
} else {
  currentUserPosts[postIndex] = upsertParams;
}


Complete function:

const upsertIntoApolloCache = (upsertParams) =&gt; {
  try {
    const data = client.readQuery({
      query: USER_POSTS_QUERY,
    });
    const currentUserPosts = data.currentUser.posts;

    const postIndex = currentUserPosts.findIndex(
      post =&gt; post.id === upsertParams.tempId || post.id === upsertParams.id
    );
    if (postIndex === -1) {
      currentUserPosts.push(upsertParams);
    } else {
      currentUserPosts[postIndex] = upsertParams;
    }

    client.writeQuery({
      query: USER_POSTS_QUERY,
      data,
    });
  } catch (error) {
    console.log('!!ERROR in upsertIntoApolloCache!!', error);
  }
};
You can group the two conditions for finding into a single || condition, since the post.id can match only one of tempId or id.

let postIndex = currentUserPosts.findIndex(post =&gt; {
  return post.id === upsertParams.id || post.id === upsertParams.tempId
});

if (postIndex === -1) {
  currentUserPosts.push(upsertParams);
} else {
  currentUserPosts[postIndex] = upsertParams;
}


You could, if possible, also change the currentUserPosts from array to a dictionary mapping your post.id to the post itself. This entirely depends on your further usage of the currentUserPosts across application.



Based on updated question content:

let currentUserPosts = {}
for (let post of data.currentUser.posts) {
  currentUserPosts[post.id] = post
}


This way, you'd only have to check against id using the in operation:

let newId = upsertParams.id || upsertParams.tempId
if (newId in currentUserPosts)
  // do unspeakable things