JavaScript
JSON
Array Manipulation
Data Merging
Programming Tips

Combine json arrays by key, javascript

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Combining JSON arrays by key is a common JavaScript task when data arrives from multiple APIs or processing stages. The goal is usually to merge records with the same identifier while preserving fields from each source. The fastest and clearest approach for most cases is to index one array in a Map, then merge records from the other arrays. This article covers merge strategies, conflict rules, deep vs shallow behavior, and performance considerations for large datasets.

Basic Merge with Map

Suppose two arrays share id as join key:

javascript
1const a = [
2  { id: 1, name: "Ana" },
3  { id: 2, name: "Ben" }
4];
5const b = [
6  { id: 1, score: 92 },
7  { id: 3, score: 75 }
8];

Merge by key:

javascript
1const byId = new Map();
2
3for (const row of a) byId.set(row.id, { ...row });
4for (const row of b) {
5  byId.set(row.id, { ...(byId.get(row.id) || {}), ...row });
6}
7
8const merged = [...byId.values()];
9console.log(merged);

This is typically O(n + m) and scales well compared to nested loops.

Define Conflict Resolution Rules

When both arrays contain the same field, last write wins in spread merge (...existing, ...incoming). That may be wrong for your domain.

Custom resolver example:

javascript
1function mergeUser(existing, incoming) {
2  return {
3    ...existing,
4    ...incoming,
5    score: Math.max(existing?.score ?? -Infinity, incoming?.score ?? -Infinity)
6  };
7}

Use resolver functions to keep business logic explicit and testable.

Handling Missing Keys and Null Rows

Defensive checks prevent runtime errors with inconsistent payloads.

javascript
1function combineByKey(arrays, key) {
2  const map = new Map();
3
4  for (const arr of arrays) {
5    for (const item of arr) {
6      if (!item || item[key] == null) continue;
7      const id = item[key];
8      map.set(id, { ...(map.get(id) || {}), ...item });
9    }
10  }
11
12  return [...map.values()];
13}

This avoids crashes from malformed records and gives predictable output.

Deep Merge Needs Extra Logic

Object spread is shallow. Nested objects are replaced, not recursively merged.

javascript
1const left = { id: 1, prefs: { theme: "dark", lang: "en" } };
2const right = { id: 1, prefs: { lang: "fr" } };
3
4console.log({ ...left, ...right });
5// prefs becomes { lang: "fr" }

If nested merge is required, use a deep merge utility or domain-specific merge logic.

Practical Verification Workflow

A strong way to avoid regressions is to validate changes in three stages: baseline, targeted change, and repeatability. First, capture a baseline command/output before applying fixes so you can prove improvement. Second, apply one focused change at a time, then rerun the exact same check to confirm causality. Third, rerun the validation multiple times (or with nearby input variants) to ensure behavior is stable and not a one-off pass.

A simple validation template:

bash
1# 1) capture baseline behavior
2./run_case.sh > before.txt
3
4# 2) apply one targeted fix
5# edit code/config based on this article
6
7# 3) validate after change
8./run_case.sh > after.txt
9diff -u before.txt after.txt

If your stack has tests, add at least one regression test that fails before the fix and passes after it. This turns troubleshooting knowledge into durable protection against future changes. In team environments, including the exact commands used for verification in pull requests or runbooks makes results reproducible across machines and CI.

Operational Checklist for Production Use

Before shipping a fix or optimization, confirm environment parity and observability. Verify toolchain/runtime versions, capture key metrics, and define rollback criteria. A technically correct local fix can still fail in production if infrastructure assumptions differ.

bash
1# Example pre-release checks
2./lint.sh
3./test.sh
4./smoke_test.sh

A minimal release checklist usually includes: compatible dependency versions, representative test coverage, explicit monitoring signals, and a rollback plan. This discipline reduces the chance that a local solution introduces new issues under real traffic or larger datasets.

Common Pitfalls

  • Using nested loops for large arrays and creating avoidable O(n*m) behavior.
  • Relying on implicit last-write-wins without defining conflict policy.
  • Assuming spread merge performs deep merge for nested objects.
  • Failing to validate key presence on every record before indexing.
  • Mutating original objects during merge and causing side effects elsewhere.

Summary

To combine JSON arrays by key in JavaScript, index records in a Map and merge with explicit conflict rules. This pattern is efficient, readable, and easy to test. Add validation for missing keys and use deep-merge logic only when nested object semantics require it.


Course illustration
Course illustration

All Rights Reserved.