JavaScript
JSON
Array Manipulation
Data Merging
Programming Tips

Combine json arrays by key, javascript

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

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.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.