You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何深度比较对象键结构(类Lodash isEqual)及优化递归取键函数

Solution: Optimized Deep Key Extraction & Structure Comparison

Got it, let's work through this problem exactly as you described. You need a cleaner way to extract all deep keys from an object, fix the null detection issue, and then use that to compare key structures (not values) to avoid unnecessary database updates.

Optimized getKeysDeep Function

First, here's the revised function that eliminates the need for an initial empty array and properly handles null:

function getKeysDeep(obj) {
  // Handle null and non-object primitives first (fixes the typeof null quirk)
  if (obj === null || typeof obj !== 'object') {
    return [];
  }

  // Start with the current object's keys
  let keys = Object.keys(obj);

  // Recursively add keys from nested objects
  keys.forEach(key => {
    keys = keys.concat(getKeysDeep(obj[key]));
  });

  return keys;
}

Key Improvements:

  • No initial array required: Just call getKeysDeep(yourObject) directly—no more getKeysDeep([], yourObject) clutter.
  • Proper null handling: The first check explicitly skips null (since JavaScript's typeof null incorrectly returns "object") and any non-object values (strings, numbers, booleans), so we never try to extract keys from invalid targets.
  • Simplified recursion: We build the key list internally by concatenating results from nested calls, making the function self-contained and easier to read.

Using This for Structure Comparison

Now let's update your verifyDataIntegrity function to use this key extraction instead of _.isEqual, so we only update the database when the key structure changes (not when user values differ):

async verifyDataIntegrity(id, data) {
  const defaultData = _.merge(new DefaultObject(id));
  // Remove the deprecated field from default structure
  if (defaultData.hasOwnProperty('myoldsetting')) delete defaultData.myoldsetting;

  // Get sorted deep keys for both objects (sort to ignore insertion order differences)
  const dataKeys = getKeysDeep(data).sort();
  const defaultKeys = getKeysDeep(defaultData).sort();

  // Only update if key structures don't match
  if (!_.isEqual(dataKeys, defaultKeys)) {
    // Merge user's existing values into the default structure to preserve customizations
    const updatedData = _.merge({}, defaultData, data);
    await myMongoDBCollection.replaceOne({ id }, updatedData);
    return updatedData;
  } else {
    return data;
  }
}

Why This Works Better:

  • Avoids unnecessary updates: We only care about the presence/absence of keys, not their values. So if a user changed myobj1.setting1 to false, the key structure is still the same, and we skip the database call.
  • Preserves user data: Using _.merge(defaultData, data) ensures we add new keys from the default, remove deprecated ones (like myoldsetting), but keep all the user's custom values intact.
  • Order-agnostic comparison: Sorting the key arrays ensures we don't get false mismatches just because the default object and user data have keys in different insertion orders.

Bonus: Precise Nested Key Paths (Optional)

If you want even more clarity (e.g., to debug exactly which nested key is missing), you can modify the function to return full dot-separated paths instead of flat keys:

function getDeepKeyPaths(obj, parentPath = '') {
  if (obj === null || typeof obj !== 'object') {
    return [];
  }

  return Object.keys(obj).flatMap(key => {
    const currentPath = parentPath ? `${parentPath}.${key}` : key;
    return [currentPath, ...getDeepKeyPaths(obj[key], currentPath)];
  });
}

This returns keys like ["id", "myobj1", "myobj1.setting1", "myobj1.setting2", "myobj2", "myobj2.perm1"], making it trivial to spot exactly where the structure differs.

内容的提问来源于stack exchange,提问作者FireController1847

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:22:35