Javascript: объединить в одном объекте JS на разных ключах на основе значений - PullRequest
0 голосов
/ 27 апреля 2019

В моем проекте AngularJS 1.3 я пытаюсь объединить объекты с заданными ключами и объединить их.Рассмотрим приведенный ниже объект (для лучшего понимания рассмотрим ключи как столбцы таблицы):

var json = {
    "filteredTask": [{
        "Email_1202_1_1554368387884": "c@c",
        "Number_1202_2_1554368395451": "50000",
        "Number_1202_3_1554368408148": "30000",
        "Text_Field_1202_4_1554368416611": "Developer"
    }, {
        "Email_1202_1_1554368387884": "b@b",
        "Number_1202_2_1554368395451": "25000",
        "Number_1202_3_1554368408148": "20000",
        "Text_Field_1202_4_1554368416611": "QA"
    }, {
        "Email_1202_1_1554368387884": "a@a",
        "Number_1202_2_1554368395451": "22000",
        "Number_1202_3_1554368408148": "20000",
        "Text_Field_1202_4_1554368416611": "Developer"
    }, {
        "Text_Field_1202_1_1554367796776": "c@c",
        "Text_Field_1202_2_1554367980023": "Admin",
        "Text_Field_1202_3_1554367980751": "HR"
    }, {
        "Text_Field_1202_1_1554367796776": "b@b",
        "Text_Field_1202_2_1554367980023": "Non Technical",
        "Text_Field_1202_3_1554367980751": "QA"
    }, {
        "Text_Field_1202_1_1554367796776": "a@a",
        "Text_Field_1202_2_1554367980023": "Technical",
        "Text_Field_1202_3_1554367980751": "Developer"
    }],
    "filter": {
        "joinField": [{
            "formField": {
                "new_key": "Text_Field_1202_1_1554367796776"
            },
            "withFormField": {
                "new_key": "Email_1202_1_1554368387884"
            }
        }, {
            "formField": {
                "new_key": "Text_Field_1202_3_1554367980751"
            },
            "withFormField": {
                "new_key": "Text_Field_1202_4_1554368416611"
            }
        }]
    }
};

Обратите внимание, filteredTask содержит все данные, а filter содержит информацию ключа присоединяемого поля.

Теперь я хочу выполнить соединение так же, как SQL на JSON.Например, присоединитесь к двум ключам Text_Field_1202_1_1554367796776 и Email_1202_1_1554368387884 (соответствие электронной почты, например, a @ a, b @ b & c @ c), результат должен быть таким же, как показано ниже.

[{
    "Email_1202_1_1554368387884": "c@c",
    "Number_1202_2_1554368395451": "50000",
    "Number_1202_3_1554368408148": "30000",
    "Text_Field_1202_4_1554368416611": "Developer",
    "Text_Field_1202_1_1554367796776": "c@c",
    "Text_Field_1202_2_1554367980023": "Admin",
    "Text_Field_1202_3_1554367980751": "HR"
}, {
    "Email_1202_1_1554368387884": "b@b",
    "Number_1202_2_1554368395451": "25000",
    "Number_1202_3_1554368408148": "20000",
    "Text_Field_1202_4_1554368416611": "QA",
    "Text_Field_1202_1_1554367796776": "b@b",
    "Text_Field_1202_2_1554367980023": "Non Technical",
    "Text_Field_1202_3_1554367980751": "QA"
}, {
    "Email_1202_1_1554368387884": "a@a",
    "Number_1202_2_1554368395451": "22000",
    "Number_1202_3_1554368408148": "20000",
    "Text_Field_1202_4_1554368416611": "Developer",
    "Text_Field_1202_1_1554367796776": "a@a",
    "Text_Field_1202_2_1554367980023": "Technical",
    "Text_Field_1202_3_1554367980751": "Developer"
}]

Теперь,если я выполняю два соединения, например Text_Field_1202_1_1554367796776 с Email_1202_1_1554368387884 (электронная почта) и Text_Field_1202_3_1554367980751 с Text_Field_1202_4_1554368416611 (обозначение), то результат должен быть примерно таким, как показано ниже, с учетом совпадения электронной почты и обозначения:

[{
    "Email_1202_1_1554368387884": "b@b",
    "Number_1202_2_1554368395451": "25000",
    "Number_1202_3_1554368408148": "20000",
    "Text_Field_1202_4_1554368416611": "QA",
    "Text_Field_1202_1_1554367796776": "b@b",
    "Text_Field_1202_2_1554367980023": "Non Technical",
    "Text_Field_1202_3_1554367980751": "QA"
}, {
    "Email_1202_1_1554368387884": "a@a",
    "Number_1202_2_1554368395451": "22000",
    "Number_1202_3_1554368408148": "20000",
    "Text_Field_1202_4_1554368416611": "Developer",
    "Text_Field_1202_1_1554367796776": "a@a",
    "Text_Field_1202_2_1554367980023": "Technical",
    "Text_Field_1202_3_1554367980751": "Developer"
}]

Я пробовал утилиты lodash library для этого.

angular.forEach(json.filter.joinField, function (jField) {
    var obj1 = _.filter(json.filteredTask, function (o1) {
        return o1[jField.formField.new_key];
    });

    var obj2 = _.filter(json.filteredTask, function (o2) {
        return o2[jField.withFormField.new_key];
    });

    // for intersaction data
    var result = _.intersectionWith(_.cloneDeep(obj1), obj2, function (x, y) {
        //Improvement needed here: when I print, it shows different keys and values and generated output differently.
        return x[jField.formField.new_key] === y[jField.withFormField.new_key] && _.assign(x, y);
    });

    json.filteredTask = result;
});
console.log(json);

Дайте мне знать, можем ли мы достичь этого любым другим способом или этот можно улучшить.

1 Ответ

2 голосов
/ 27 апреля 2019

Вот шаги, которые вы можете предпринять:

  1. Извлеките условия соединения из данных "joinField", чтобы вы получили простые [a, b] пары
  2. Для каждой строки определитена какой стороне соединения оно находится: если в строке присутствует левое поле первого условия соединения, то оно слева.
  3. Создайте составной ключ из полей, перечисленных в условиях соединения -на стороне, на которой находится запись
  4. Сгруппируйте строки по их составному ключу: для левой и для правой сторон будут группы
  5. Объедините строки из левой и правой группдля того же ключа: это декартово произведение
  6. Объединить все эти результаты

Вот как вы могли бы сделать это в ES2018:

function join(obj) {
    // Extract join conditions
    const keys = obj.filter.joinField.map(pair => 
                     [pair.withFormField.new_key, pair.formField.new_key]);
    const grouped = [new Map, new Map]; // groups for left & right side
    const result = [];
    // Put rows in buckets based on their join fields
    for (const row of obj.filteredTask) {
        // Determine which "side" of the join this row is on
        let side = +(keys[0][1] in row);
        // Create single key value:
        let key = JSON.stringify(keys.map(pair => row[pair[side]]));
        if (!grouped[side].has(key)) grouped[side].set(key, []);
        grouped[side].get(key).push(row);
    }
    // Perform the join
    for (const [key, rows1] of grouped[0]) {
        // pick up rows from the other side that share the same key (intersection)
        const rows2 = grouped[1].get(key);
        if (!rows2) continue;
        for (const row1 of rows1) {
            for (const row2 of rows2) result.push({...row1, ...row2});
        }
    }
    return result;
}

var data = {"filteredTask": [{"Email_1202_1_1554368387884": "c@c","Number_1202_2_1554368395451": "50000","Number_1202_3_1554368408148": "30000","Text_Field_1202_4_1554368416611": "Developer"}, {"Email_1202_1_1554368387884": "b@b","Number_1202_2_1554368395451": "25000","Number_1202_3_1554368408148": "20000","Text_Field_1202_4_1554368416611": "QA"}, {"Email_1202_1_1554368387884": "a@a","Number_1202_2_1554368395451": "22000","Number_1202_3_1554368408148": "20000","Text_Field_1202_4_1554368416611": "Developer"}, {"Text_Field_1202_1_1554367796776": "c@c","Text_Field_1202_2_1554367980023": "Admin","Text_Field_1202_3_1554367980751": "HR"}, {"Text_Field_1202_1_1554367796776": "b@b","Text_Field_1202_2_1554367980023": "Non Technical","Text_Field_1202_3_1554367980751": "QA"}, {"Text_Field_1202_1_1554367796776": "a@a","Text_Field_1202_2_1554367980023": "Technical","Text_Field_1202_3_1554367980751": "Developer"}],"filter": {"joinField": [{"formField": {"new_key": "Text_Field_1202_1_1554367796776"},"withFormField": {"new_key": "Email_1202_1_1554368387884"}}, {"formField": {"new_key": "Text_Field_1202_3_1554367980751"},"withFormField": {"new_key": "Text_Field_1202_4_1554368416611"}}]}};

const result = join(data);

console.log(result);

В ES5:

function join(obj) {
    // Extract join conditions
    var keys = obj.filter.joinField.map(pair => 
                     [pair.withFormField.new_key, pair.formField.new_key]);
    var grouped = [{}, {}]; // groups for left & right side
    var result = [];
    // Put rows in buckets based on their join fields
    obj.filteredTask.forEach(function (row) {
        // Determine which "side" of the join this row is on
        var side = +(keys[0][1] in row);
        // Create single key value:
        var key = JSON.stringify(keys.map(function (pair) {
            return row[pair[side]];
        }));
        if (!grouped[side][key]) grouped[side][key] = [];
        grouped[side][key].push(row);
    });
    // Perform the join
    for (var key in grouped[0]) {
        var rows1 = grouped[0][key];
        // pick up rows from the other side that share the same key (intersection)
        var rows2 = grouped[1][key];
        if (!rows2) continue;
        rows1.forEach(function (row1) {
            rows2.forEach(function (row2) {
                result.push(Object.assign({}, row1, row2)); 
            });
        });
    }
    return result;
}

var data = {"filteredTask": [{"Email_1202_1_1554368387884": "c@c","Number_1202_2_1554368395451": "50000","Number_1202_3_1554368408148": "30000","Text_Field_1202_4_1554368416611": "Developer"}, {"Email_1202_1_1554368387884": "b@b","Number_1202_2_1554368395451": "25000","Number_1202_3_1554368408148": "20000","Text_Field_1202_4_1554368416611": "QA"}, {"Email_1202_1_1554368387884": "a@a","Number_1202_2_1554368395451": "22000","Number_1202_3_1554368408148": "20000","Text_Field_1202_4_1554368416611": "Developer"}, {"Text_Field_1202_1_1554367796776": "c@c","Text_Field_1202_2_1554367980023": "Admin","Text_Field_1202_3_1554367980751": "HR"}, {"Text_Field_1202_1_1554367796776": "b@b","Text_Field_1202_2_1554367980023": "Non Technical","Text_Field_1202_3_1554367980751": "QA"}, {"Text_Field_1202_1_1554367796776": "a@a","Text_Field_1202_2_1554367980023": "Technical","Text_Field_1202_3_1554367980751": "Developer"}],"filter": {"joinField": [{"formField": {"new_key": "Text_Field_1202_1_1554367796776"},"withFormField": {"new_key": "Email_1202_1_1554368387884"}}, {"formField": {"new_key": "Text_Field_1202_3_1554367980751"},"withFormField": {"new_key": "Text_Field_1202_4_1554368416611"}}]}};

var result = join(data);

console.log(result);
...