Two lists of the same people, both partly out of date. mergeByKeyNewestWins(listA, listB, keyField, dateField) merges row objects by a key (like Email), case- and whitespace-insensitive. When both lists have a record, the newer one's non-blank fields win and the older one fills the gaps.
When to use
- Merging a CRM export with a sign-up sheet
- Combining two team contact lists without losing a phone number
- Any merge where "most recently updated" should decide conflicts
How to use this snippet
/**
* Merge row objects by key; newer (by dateField) non-blank values win.
* Rows with a blank key are dropped. Order follows first appearance.
*
* @param {Object[]} listA
* @param {Object[]} listB
* @param {string} keyField e.g. 'Email'
* @param {string} dateField e.g. 'Updated'
* @return {Object[]}
*/
function mergeByKeyNewestWins(listA, listB, keyField, dateField) {
var norm = function (v) { return String(v == null ? '' : v).trim().toLowerCase(); };
var time = function (r) { var t = new Date(r[dateField]).getTime(); return isNaN(t) ? -Infinity : t; };
var byKey = {}, order = [];
listA.concat(listB).forEach(function (row) {
var k = norm(row[keyField]);
if (!k) return;
var cur = byKey[k];
if (!cur) { byKey[k] = row; order.push(k); return; }
var newer = time(row) >= time(cur) ? row : cur;
var older = newer === row ? cur : row;
var merged = {};
Object.keys(older).forEach(function (f) { merged[f] = older[f]; });
Object.keys(newer).forEach(function (f) {
if (newer[f] !== '' && newer[f] != null) merged[f] = newer[f];
});
byKey[k] = merged;
});
return order.map(function (k) { return byKey[k]; });
}
Example
var a = [{ Email: 'ada@x.com', Phone: '555-0100', City: 'NYC', Updated: '2027-01-01' }];
var b = [{ Email: 'ADA@x.com ', Phone: '555-0199', City: '', Updated: '2027-02-01' }];
mergeByKeyNewestWins(a, b, 'Email', 'Updated');
// → [{ Email: 'ADA@x.com ', Phone: '555-0199', City: 'NYC', Updated: '2027-02-01' }]
Tips:
- A blank in the newer row doesn't erase the older value. That's on purpose: a missing field usually means "not collected", not "deleted".
- Rows without a valid date count as oldest.
- The key is kept as the newer row typed it. Trim or lowercase it on write if you want a clean column.
Happy Coding!
