简体   繁体   English

Javascript-将对象添加到对象-如何处理数组?

[英]Javascript - Adding objects to an object - how to handle arrays?

Working with a javascript object, I am struggling to figure out how to add new data (specifically more objects) to it. 我正在使用javascript对象努力解决如何向其中添加新数据(特别是更多对象)的问题。 When it comes to adding data, I am not sure how to turn the existing value into an array of objects. 在添加数据时,我不确定如何将现有值转换为对象数组。

Here is an example of my object: 这是我的对象的一个​​示例:

It's pretty straight forward, doesn't contain any arrays at this point. 非常简单,目前不包含任何数组。 This is where I get stuck. 这就是我卡住的地方。

var obj = {
  "data": {
    "VersionForTarget": "1",
    "RulesContainer": {
      "Rule": { // <--- New Rule Goes Here
        "RuleParentID": "1",
        "RuleVersionID": "1",
        "MappedValue": "1",
        "ProcessingOrder": "1",
        "MetaInsertUtc": "2017-03-03T17:54:34.643",
        "Value": "Omaha",
        "IsRuleRetired": "0",
        "UserImpactCount": "2277",
        "AttributeContainer": {
          "Attribute": { // <--- New Attribute Goes Here
            "AttributeID": "6",
            "AttributeName": "Campus",
            "AttributeDetailsContainer": {
              "AttributeDetails": { // <--- New Attribute Details Goes Here
                "RuleDetailID": "1",
                "AttributeID": "6",
                "OperatorID": "3",
                "AttributeValue": "1",
                "RuleParentID": "1",
                "Value": "Omaha",
                "IsValueRetired": "0",
                "OperatorName": "In List",
                "SqlOperator": "IN"
              }
            }
          }
        }
      }
    }
  }
};

If I wanted to add a new object of data to Rule , Rule then becomes an array of Rule objects. 如果我想向Rule添加一个新的数据对象,则Rule将成为Rule对象的数组。

What I am going for: 我要做什么:

I am essentially trying to make three functions. 我实质上是在尝试实现三个功能。 One that will add a Rule , one that will add an Attribute to a specified rule, and one that adds AttributeDetails to a specified attribute in a specified rule. 一种将添加Rule ,一种将Attribute添加到指定的规则,另一种将AttributeDetails添加到指定规则的指定属性。

// This will add a new rule
function addRule() {

  var newRule = {
    "RuleParentID": "3",
    "RuleVersionID": "1",
    "MappedValue": "4",
    "ProcessingOrder": "5",
    "MetaInsertUtc": "2017-03-03T17:54:34.643",
    "Value": "New Thing",
    "IsRuleRetired": "0",
    "UserImpactCount": "2277"
  };

}


// This will add a new attribute
function addAttribute(RuleParentID) {

  // Add attribute object in our parent rule

  var newAttribute = {
    "AttributeID": "6",
    "AttributeName": "Campus",
  }

}


// This will add new attribute details
function addAttributeDetails(RuleParentID, AttributeID) {

  // Add attribute details to our specified attribute in our specified parent rule

  var newAttributeDetails = {
    "RuleDetailID": "1",
    "AttributeID": "6",
    "OperatorID": "3",
    "AttributeValue": "1",
    "RuleParentID": "1",
    "Value": "Omaha",
    "IsValueRetired": "0",
    "OperatorName": "In List",
    "SqlOperator": "IN"
  }

}

My Question 我的问题

What are some approaches I can take to a take like this? 我可以采取哪些方法? I thought about looping through the data RuleContainer for example but Rule could either may or may not be an array. 例如,我考虑过遍历数据RuleContainer ,但是Rule可以是数组,也可以不是数组。

I have read through some of the documentation for lodash and have used some of the functions like _find to at least get my bearings on where I need to manipulate but then I can't figure out where to go from there. 我通读了lodash一些文档,并使用了诸如_find之类的一些功能,以至少了解我需要操纵的位置,但后来我不知道该从哪里去。

Any suggestions? 有什么建议么?

Here is a fiddle of this setup with an example of the outcome that would be possible with such working functions. 这是此设置的一个小技巧,并提供了使用此类工作功能可能产生的结果的示例。

https://jsfiddle.net/tor1t2q6/1/ https://jsfiddle.net/tor1t2q6/1/

To solve your problem you could have RuleContainer be an array instead of an object. 为了解决您的问题,您可以让RuleContainer是数组而不是对象。

var obj = {
  "data": {
    "VersionForTarget": "1",
    "RulesContainer": [//array bracket
      "Rule": { // <--- New Rule Goes Here
        "RuleParentID": "1",
        "RuleVersionID": "1",
        "MappedValue": "1",
        "ProcessingOrder": "1",
        "MetaInsertUtc": "2017-03-03T17:54:34.643",
        "Value": "Omaha",
        "IsRuleRetired": "0",
        "UserImpactCount": "2277",
        "AttributeContainer": {
          "Attribute": { // <--- New Attribute Goes Here
            "AttributeID": "6",
            "AttributeName": "Campus",
            "AttributeDetailsContainer": {
              "AttributeDetails": { // <--- New Attribute Details Goes Here
                "RuleDetailID": "1",
                "AttributeID": "6",
                "OperatorID": "3",
                "AttributeValue": "1",
                "RuleParentID": "1",
                "Value": "Omaha",
                "IsValueRetired": "0",
                "OperatorName": "In List",
                "SqlOperator": "IN"
              }
            }
          }
        }
      }
    ]
  }
};

I made some changes in your fiddle along the lines of what I think you're asking. 我按照您认为的要求对您的小提琴进行了一些更改。 The gist of it is that you can just transform the 'Rule' object into an array from the get-go and then not worry about it, and that should work regardless of whether Rule is given to you initially as an array or an object. 其要点是,您可以从一开始就将“ Rule”对象转换为数组,然后不必担心它,并且不管Rule最初是作为数组还是对象提供给您,这都应该起作用。

const objectWithRuleAsArray = initRuleArray(obj);
function initRuleArray(object) {
    if(Array.isArray(object.data.RulesContainer.Rule)) {
    return object;
  } else {
    const ruleData = object.data.RulesContainer.Rule;
    object.data.RulesContainer.Rule = []
    object.data.RulesContainer.Rule.push(ruleData);
    return object;
  }
}
let rulesArray = objectWithRuleAsArray.data.RulesContainer.Rule
rulesArray.push(addRule());
console.log('Created Rules Array & Added Rule', rulesArray);

Then from there you can start to add your functions which modify the the array (& objects in the array) as needed. 然后从那里开始添加需要的函数,这些函数可以根据需要修改数组(数组中的&对象)。 Here going through the array to find the correct ID, then adding the new properties to that object. 这里遍历数组以找到正确的ID,然后将新属性添加到该对象。

// This will add a new attribute to the object
function addAttribute(p_array, p_ruleParentID) {

  var newAttribute = {
    "AttributeID": "6",
    "AttributeName": "Campus",
  }

    // Add attribute object in our parent rule
    p_array.forEach((item, index)=>{
    console.log(item, index)
    // note that the IDs here are saved as strings, not numbers
    if(parseInt(item.RuleParentID, 10) === p_ruleParentID) {
        console.log('found id');
      for(const prop in newAttribute) {
        if (newAttribute.hasOwnProperty(prop)) {
            item[prop] = newAttribute[prop]
        }
      }
    }
  })

  return p_array;

}

rulesArray = addAttribute(rulesArray, 3);
console.log('Added Attribute', rulesArray);

Modified fiddle: https://jsfiddle.net/04podo35/2/ 修改过的小提琴: https : //jsfiddle.net/04podo35/2/

As you don't mention about your purpose of storing and updating the JSON data, I will assume that the data is used for simple CRUD operations. 正如您没有提到存储和更新JSON数据的目的一样,我将假定该数据用于简单的CRUD操作。 If that is the case, then it's better to consider altering the whole JSON structure. 如果是这种情况,那么最好考虑更改整个JSON结构。 The main reasons: 主要原因:

  • Difficult to perform simple operations: it mostly take O(n) time to perform search/deletion based on object's ID; 难以执行简单的操作:根据对象的ID进行搜索/删除通常需要O(n)时间; you always have to loop the whole array to get the matched one. 您总是必须遍历整个数组才能获得匹配的数组。
  • Duplication of data: Attribute will likely be duplicated whenever you want to add an Attribute to more than 1 Rule; 数据重复:只要您想将一个属性添加到多个规则中,就很可能会重复该属性; same goes for AttributeDetail. AttributeDetail也是如此。 This will also increase complexity of insertion operations. 这也将增加插入操作的复杂性。
  • Nested data structure: nesting Rule, Attribute and AttributeDetail will cost you a lot when performing operations. 嵌套数据结构:执行操作时,嵌套Rule,Attribute和AttributeDetail会花费很多。 Maintaining it will also be a chore. 维护它也很麻烦。

My suggestion: don't use array. 我的建议:不要使用数组。 Store Rule, Attribute and AttributeDetail using their IDs as key. 使用ID作为关键字存储Rule,Attribute和AttributeDetail。 In this way, you don't need to worry about whether the object is an array or not; 这样,您不必担心对象是否为数组; also it helps to simplify simple CRUD operations. 它还有助于简化简单的CRUD操作。 Here is an example of using RuleVersionID, AttributeID and combination of RuleDetailID-AttributeID to store the same data. 这是一个使用RuleVersionID,AttributeID和RuleDetailID-AttributeID的组合来存储相同数据的示例。

var obj = {
  "data": {
    "VersionForTarget": "1",
    "RulesContainer": {
      "Rule": { // <--- New Rule Goes Here
        "1": { 
          "RuleParentID": "1",
          "RuleVersionID": "1",
          "MappedValue": "1",
          "ProcessingOrder": "1",
          "MetaInsertUtc": "2017-03-03T17:54:34.643",
          "Value": "Omaha",
          "IsRuleRetired": "0",
          "UserImpactCount": "2277",
          "AttributeContainer": {
            "Attribute": { // <--- New Attribute Goes Here
              "6": {
                "AttributeID": "6",
                "AttributeName": "Campus",
                "AttributeDetailsContainer": {
                  "AttributeDetails": { // <--- New Attribute Details Goes Here
                    "1-6": {
                      "RuleDetailID": "1",
                      "AttributeID": "6",
                      "OperatorID": "3",
                      "AttributeValue": "1",
                      "RuleParentID": "1",
                      "Value": "Omaha",
                      "IsValueRetired": "0",
                      "OperatorName": "In List",
                      "SqlOperator": "IN"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
};

You can use any other attribute to be keys as long as it helps to identify objects. 您可以使用任何其他属性作为键,只要它有助于识别对象。

So your function addRule can look like this (here I use 2 lodash methods: set and has ) 因此,您的功能addRule可能如下所示(这里我使用2个lodash方法: sethas

function addRule(newRule) {
  if (has(newRule, "ruleVersionID")) {
    var path = "data.RuleContainer.Rule." + newRule.ruleVersionID;
    set(obj, path, newRule); 
    return path;
  }
  return null;
}

I also strongly recommend you to flatten your data: keeping Rule, Attribute, AttributeDetail in the same level. 我也强烈建议您整理数据:将Rule,Attribute,AttributeDetail保持在同一级别。 Here is an example of keeping them away from each other: 这是使它们彼此远离的示例:

var obj = {
  "data": {
    "VersionForTarget": "1",
    "RulesContainer": {
      "Rule": {
        "1": {
          "RuleParentID": "1",
          "RuleVersionID": "1",
          "MappedValue": "1",
          "ProcessingOrder": "1",
          "MetaInsertUtc": "2017-03-03T17:54:34.643",
          "Value": "Omaha",
          "IsRuleRetired": "0",
          "UserImpactCount": "2277"
        }
      }
    },
    "AttributeContainer": {
      "Attribute": {
        "6": {
          "AttributeID": "6",
          "AttributeName": "Campus",
        }
      }
    },
    "AttributeDetailsContainer": {
      "AttributeDetails": {
        "1-6": {
          "RuleDetailID": "1",
          "AttributeID": "6",
          "OperatorID": "3",
          "AttributeValue": "1",
          "RuleParentID": "1",
          "Value": "Omaha",
          "IsValueRetired": "0",
          "OperatorName": "In List",
          "SqlOperator": "IN"
        }
      }
    }
  }
};

For more details, you can read this documentation about JSON normalization. 有关更多详细信息,您可以阅读有关JSON规范化的本文档 This is where my solution comes from. 这就是我的解决方案的来源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM