На входе есть данные, которые выглядят примерно так:
var cache = { cat: [{"id":1, "name":"Сладкий"}, {"id":2, "name":"Горький"}], tag: [{"id":1, "name":"Сахар"}, {"id":2, "name":"Перец"}], tag_to_cat: [ {"tag_id":1, "cat_id":1}, {"tag_id":1, "cat_id":2}, // 'Сладкий Сахар', 'Горький Сахар' {"tag_id":2, "cat_id":1}, {"tag_id":2, "cat_id":2}, // 'Сладкий Перец', 'Горький Перец' ] }
На выходе нужно получить:
cache.tag_by_cat: [ {"id":1,"name":"Сладкий","path":"Сладкий/","tag":[ {"id":1,"name":"Сахар","path":"Сладкий/Сахар/"}, {"id":2,"name":"Перец","path":"Сладкий/Перец/"}]}, {"id":2,"name":"Горький","path":"Горький/","tag":[ {"id":1,"name":"Сахар","path":"Горький/Сахар/"}, {"id":2,"name":"Перец","path":"Горький/Перец/"}]} ]
Если начну рассказывать зачем - затяну песню на неделю... просто нужно :).
Открываем блокнот, я использую Notepad++, пишем код:
var cache = { cat: [{"id":1, "name":"Сладкий"}, {"id":2, "name":"Горький"}], tag: [{"id":1, "name":"Сахар"}, {"id":2, "name":"Перец"}], tag_to_cat: [ {"tag_id":1, "cat_id":1}, {"tag_id":1, "cat_id":2}, // 'Сладкий Сахар', 'Горький Сахар' {"tag_id":2, "cat_id":1}, {"tag_id":2, "cat_id":2}, // 'Сладкий Перец', 'Горький Перец' ] } cache.tag_by_cat = cache.cat.map(function(cat) { cat.path = cat.name + '/'; cat.tag = cache.tag.filter(function(tag) { return cache.tag_to_cat.filter(function(tag_to_cat) { return tag_to_cat.cat_id == cat.id; }).map(function(tag_to_cat) { return tag_to_cat.tag_id }).indexOf(tag.id) !== -1; }).map(function(tag) { tag.path = cat.path + tag.name + '/'; return tag; }); return cat; }); console.log('cache.tag_by_cat: ', JSON.stringify(cache.tag_by_cat));
Выполняем:
Получаем следующий объект:
cache.tag_by_cat: [ {"id":1,"name":"Сладкий","path":"Сладкий/","tag":[ {"id":1,"name":"Сахар","path":"Горький/Сахар/"}, {"id":2,"name":"Перец","path":"Горький/Перец/"}]}, {"id":2,"name":"Горький","path":"Горький/","tag":[ {"id":1,"name":"Сахар","path":"Горький/Сахар/"}, {"id":2,"name":"Перец","path":"Горький/Перец/"}]} ]
Тысяча чертей, сударь! Где мой Сладкий Сахар и Сладкий Перец?
Переписываем код "по-стариковски" - без мапов и фильтров - по-моему так будет понятнее что происходит:
var cache = { cat: [{"id":1, "name":"Сладкий"}, {"id":2, "name":"Горький"}], tag: [{"id":1, "name":"Сахар"}, {"id":2, "name":"Перец"}], tag_to_cat: [ {"tag_id":1, "cat_id":1}, {"tag_id":1, "cat_id":2}, // 'Сладкий Сахар', 'Горький Сахар' {"tag_id":2, "cat_id":1}, {"tag_id":2, "cat_id":2}, // 'Сладкий Перец', 'Горький Перец' ] } cache.tag_by_cat = []; for (var i=0; i<cache.cat.length; i++) { cache.cat[i].path = cache.cat[i].name + '/'; cache.cat[i].tag = []; for (var j=0; j<cache.tag_to_cat.length; j++) { if (cache.tag_to_cat[j].cat_id === cache.cat[i].id) { for (var k=0; k<cache.tag.length; k++) { if (cache.tag[k].id === cache.tag_to_cat[j].tag_id) { cache.tag[k].path = cache.cat[i].path + cache.tag[k].name + '/'; cache.cat[i].tag.push(cache.tag[k]); break; } } } } cache.tag_by_cat.push(cache.cat[i]); } console.log('cache.tag_by_cat: ', JSON.stringify(cache.tag_by_cat));
Выполняем:
То же самое. Но теперь можно понять куда пропал Сладкий Сахар и Сладкий Перец.
Добавим в код пару строчек для вывода в консоль свойств исходных объектов cache.cat и cache.tag:
console.log('cache.cat: ', JSON.stringify(cache.cat)); console.log('cache.tag: ', JSON.stringify(cache.tag));
Выполним код еще раз:
Получаем следующие объекты:
cache.cat: [ {"id":1,"name":"Сладкий","path":"Сладкий/","tag":[ {"id":1,"name":"Сахар","path":"Горький/Сахар/"}, {"id":2,"name":"Перец","path":"Горький/Перец/"}]}, {"id":2,"name":"Горький","path":"Горький/","tag":[ {"id":1,"name":"Сахар","path":"Горький/Сахар/"}, {"id":2,"name":"Перец","path":"Горький/Перец/"}]} ] cache.tag: [ {"id":1,"name":"Сахар","path":"Горький/Сахар/"}, {"id":2,"name":"Перец","path":"Горький/Перец/"} ]
Становится понятно, что изменять свойства иходных объектов нам ни к чему, а нужно эти самые объекты как-то клонировать.
Первое, что приходит на ум - JSON.parse(JSON.stringify(obj)):
var cache = { cat: [{"id":1, "name":"Сладкий"}, {"id":2, "name":"Горький"}], tag: [{"id":1, "name":"Сахар"}, {"id":2, "name":"Перец"}], tag_to_cat: [ {"tag_id":1, "cat_id":1}, {"tag_id":1, "cat_id":2}, // 'Сладкий Сахар', 'Горький Сахар' {"tag_id":2, "cat_id":1}, {"tag_id":2, "cat_id":2}, // 'Сладкий Перец', 'Горький Перец' ] } cache.tag_by_cat = []; var cat, tag; for (var i=0; i<cache.cat.length; i++) { cat = JSON.parse(JSON.stringify(cache.cat[i])); cat.path = cat.name + '/'; cat.tag = []; for (var j=0; j<cache.tag_to_cat.length; j++) { if (cache.tag_to_cat[j].cat_id === cache.cat[i].id) { for (var k=0; k<cache.tag.length; k++) { if (cache.tag[k].id === cache.tag_to_cat[j].tag_id) { tag = JSON.parse(JSON.stringify(cache.tag[k])); tag.path = cat.path + tag.name + '/'; cat.tag.push(tag); break; } } } } cache.tag_by_cat.push(cat); } console.log('cache.tag_by_cat: ', JSON.stringify(cache.tag_by_cat));
Выполняем:
Bingo! То, что нужно:
cache.tag_by_cat: [ {"id":1,"name":"Сладкий","path":"Сладкий/","tag":[ {"id":1,"name":"Сахар","path":"Сладкий/Сахар/"}, {"id":2,"name":"Перец","path":"Сладкий/Перец/"}]}, {"id":2,"name":"Горький","path":"Горький/","tag":[ {"id":1,"name":"Сахар","path":"Горький/Сахар/"}, {"id":2,"name":"Перец","path":"Горький/Перец/"}]} ]
Но, согласитесь, как-то не по фэн-шую.
Еще один вариант - Object.create():
var cache = { cat: [{"id":1, "name":"Сладкий"}, {"id":2, "name":"Горький"}], tag: [{"id":1, "name":"Сахар"}, {"id":2, "name":"Перец"}], tag_to_cat: [ {"tag_id":1, "cat_id":1}, {"tag_id":1, "cat_id":2}, // 'Сладкий Сахар', 'Горький Сахар' {"tag_id":2, "cat_id":1}, {"tag_id":2, "cat_id":2}, // 'Сладкий Перец', 'Горький Перец' ] } cache.tag_by_cat = []; var cat, tag; for (var i=0; i<cache.cat.length; i++) { cat = Object.create(cache.cat[i]); cat.path = cat.name + '/'; cat.tag = []; for (var j=0; j<cache.tag_to_cat.length; j++) { if (cache.tag_to_cat[j].cat_id === cache.cat[i].id) { for (var k=0; k<cache.tag.length; k++) { if (cache.tag[k].id === cache.tag_to_cat[j].tag_id) { tag = Object.create(cache.tag[k]); tag.path = cat.path + tag.name + '/'; cat.tag.push(tag); break; } } } } cache.tag_by_cat.push(cat); } console.log('cache.tag_by_cat: ', JSON.stringify(cache.tag_by_cat));
Выполняем:
Все ОК. На первый взгляд не совсем - не видим свойства объекта, унаследованные от прототипа, но они есть, просто "by default properties ARE NOT writable, enumerable or configurable".
Для того, чтобы убедиться в их существовании добавим в код несколько строчек:
cache.tag_by_cat.forEach(function(cat) { console.log('cat.id: ' + cat.id + '\n' + 'cat.name: ' + cat.name + '\n' + 'cat.tag: ' + JSON.stringify(cat.tag)); cat.tag.forEach(function(tag) { console.log('tag.id: ' + tag.id + '\n' + 'tag.name: ' + tag.name + '\n' + 'tag.path: ' + tag.path); }); });
Выполняем:
Теперь точно все ОК.
Еще один, "нативный" для Node.js, вариант с использованием require('util')._extend:
var extend = require('util')._extend; var cache = { cat: [{"id":1, "name":"Сладкий"}, {"id":2, "name":"Горький"}], tag: [{"id":1, "name":"Сахар"}, {"id":2, "name":"Перец"}], tag_to_cat: [ {"tag_id":1, "cat_id":1}, {"tag_id":1, "cat_id":2}, // 'Сладкий Сахар', 'Горький Сахар' {"tag_id":2, "cat_id":1}, {"tag_id":2, "cat_id":2}, // 'Сладкий Перец', 'Горький Перец' ] } cache.tag_by_cat = []; var cat, tag; for (var i=0; i<cache.cat.length; i++) { cat = extend({path: cache.cat[i].name + '/'}, cache.cat[i]) cat.tag = []; for (var j=0; j<cache.tag_to_cat.length; j++) { if (cache.tag_to_cat[j].cat_id === cache.cat[i].id) { for (var k=0; k<cache.tag.length; k++) { if (cache.tag[k].id === cache.tag_to_cat[j].tag_id) { tag = extend({path: cat.path + cache.tag[k].name + '/'}, cache.tag[k]) cat.tag.push(tag); break; } } } } cache.tag_by_cat.push(cat); } console.log('cache.tag_by_cat: ', JSON.stringify(cache.tag_by_cat));
Выполняем:
Окончательный вариант кода может выглядеть следующим образом:
var extend = require('util')._extend; var cache = { cat: [{"id":1, "name":"Сладкий"}, {"id":2, "name":"Горький"}], tag: [{"id":1, "name":"Сахар"}, {"id":2, "name":"Перец"}], tag_to_cat: [ {"tag_id":1, "cat_id":1}, {"tag_id":1, "cat_id":2}, // 'Сладкий Сахар', 'Горький Сахар' {"tag_id":2, "cat_id":1}, {"tag_id":2, "cat_id":2}, // 'Сладкий Перец', 'Горький Перец' ] } cache.tag_by_cat = cache.cat.map(function(cat) { cat = extend({path: cat.name + '/'}, cat) cat.tag = cache.tag.filter(function(tag) { return cache.tag_to_cat.filter(function(tag_to_cat) { return tag_to_cat.cat_id == cat.id; }).map(function(tag_to_cat) { return tag_to_cat.tag_id }).indexOf(tag.id) !== -1; }).map(function(tag) { return extend({path: cat.path + tag.name + '/'}, tag); }); return cat; }); console.log('cache.tag_by_cat: ', JSON.stringify(cache.tag_by_cat));
Вот как-то так. Есть вариант лучше?
Комментариев нет:
Отправить комментарий
Комментарий будет опубликован после модерации