获取父数组及其所有子数组

get array of parent and all of its child

假设我有这样的数据...

data = [{
    "_id" : "1",
    "parentId" : "thisPostId",
    "topLevelId" : "1",
    "text" : "<p>comment</p>",
},
{
    "_id" : "2",
    "parentId" : "1",
    "topLevelId" : "1",
    "text" : "<p>reply to comment</p>",
},
{
    "_id" : "3",
    "parentId" : "2",
    "topLevelId" : "1",
    "text" : "<p>reply to reply to comment</p>",
},
{
    "_id" : "4",
    "parentId" : "3",
    "topLevelId" : "1",
    "text" : "<p>reply to reply to reply to comment</p>",
}]

我需要删除评论及其所有子项...

如果要删除的评论是 _id:1, 那么我需要一个 ["1","2","3","4"], 那么我可以 运行 Coll.remove({_id:{$in:["1","2","3","4"]}}, callback);

如果要删除的评论是 _id:2,那么我需要一个 ["2","3","4"]

的数组

如果要删除的评论是 _id:3,那么我需要一个 ["3","4"]

的数组

如果要删除的评论是 _id:4,那么我需要一个 ["4"]

的数组

我试过了(不知道)...

_.forEach(data, function(value, key){
    _.pluck(_.where(key, { "parentId" : "2" }), '_id');
});

并且不工作...

任何有关 javascript/lodash/underscore 的帮助将不胜感激,

谢谢...

First of all, you need to get the index of the item having mentioned _id, If item exists in the array then you can use array.splice to remove the n elements from mentioned index. To get items from the deleted node, deepcopy of the array is stored in temperory variable.

The splice() method changes the content of an array by removing existing elements and/or adding new elements.

您可以使用data.length - index

计算删除次数

var data = [{
  "_id": "1",
  "parentId": "thisPostId",
  "topLevelId": "1",
  "text": "<p>comment</p>",
}, {
  "_id": "2",
  "parentId": "1",
  "topLevelId": "1",
  "text": "<p>reply to comment</p>",
}, {
  "_id": "3",
  "parentId": "2",
  "topLevelId": "1",
  "text": "<p>reply to reply to comment</p>",
}, {
  "_id": "4",
  "parentId": "3",
  "topLevelId": "1",
  "text": "<p>reply to reply to reply to comment</p>",
}];
var getIndex = function(_id) {
  for (var i = 0; i < data.length; i++) {
    if (data[i]._id == _id) {
      return i;
    }
  }
};

function deepCopy(obj) {
 if (null == obj || "object" != typeof obj) return obj;
  var copy = obj.constructor();
  for (var attr in obj) {
    if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
  }
  return copy;
}
var _id = 1;

var index = getIndex(_id);
var _temp = deepCopy(data);
var removedData = data.splice(index, 1);
alert(removedData);
if (typeof index !== 'undefined') {
  var neededData = _temp.splice(index, (_temp.length - index));
  alert(neededData);
}

Fiddle here

试试这个:

HTML:

<input type="text" id="Txt" />

<button type="button" onclick="check();">
Check
</button>

JS:

data = [{
    "_id" : "1",
    "parentId" : "thisPostId",
    "topLevelId" : "1",
    "text" : "<p>comment</p>",
},
{
    "_id" : "2",
    "parentId" : "1",
    "topLevelId" : "1",
    "text" : "<p>reply to comment</p>",
},
{
    "_id" : "3",
    "parentId" : "2",
    "topLevelId" : "1",
    "text" : "<p>reply to reply to comment</p>",
},
{
    "_id" : "4",
    "parentId" : "3",
    "topLevelId" : "1",
    "text" : "<p>reply to reply to reply to comment</p>",
}];


function check() {
    getIds(document.getElementById("Txt").value);
}

function getIds(id) {
    var allow = false,
        result = [];

    for (var i = 0; i < data.length; i++) {
        if (data[i]._id == id) {
            allow = true;
        }
        if (allow) {
            result.push(data[i]._id)
        }
    }

    retrun result;
}

这是另一种解释,使用本机 Array.prototype.reduce 方法仅将子元素添加到返回的数组。

edit, didn't read question properly, this will now return the current id and all children.

var data = [{
    "_id" : "1",
    "parentId" : "thisPostId",
    "topLevelId" : "1",
    "text" : "<p>comment</p>",
},
{
    "_id" : "2",
    "parentId" : "1",
    "topLevelId" : "1",
    "text" : "<p>reply to comment</p>",
},
{
    "_id" : "3",
    "parentId" : "2",
    "topLevelId" : "1",
    "text" : "<p>reply to reply to comment</p>",
},
{
    "_id" : "4",
    "parentId" : "3",
    "topLevelId" : "1",
    "text" : "<p>reply to reply to reply to comment</p>",
}];

function getChildIds( arr, id ){
  var parentFound = false;
  return arr.reduce(function( ret, item ){
    if( parentFound === false && item._id == id ){
      parentFound = true;
    } 
    
    if( parentFound ) {
      ret = ret.concat( item._id );
    }
    
    return ret;
  }, []);
}

console.log( getChildIds(data, '1') );
console.log( getChildIds(data, '2') );
console.log( getChildIds(data, '3') );
console.log( getChildIds(data, '4') );
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>

any order, not sure why it's necessary thought.

var data = [{
  "_id": "2",
  "parentId": "1",
  "topLevelId": "1",
  "text": "<p>reply to comment</p>",
}, {
  "_id": "1",
  "parentId": "thisPostId",
  "topLevelId": "1",
  "text": "<p>comment</p>",
}, {
  "_id": "4",
  "parentId": "3",
  "topLevelId": "1",
  "text": "<p>reply to reply to reply to comment</p>",
}, {
  "_id": "3",
  "parentId": "2",
  "topLevelId": "1",
  "text": "<p>reply to reply to comment</p>",
}];

function getChildIdsInAnyOrder(arr, id) {
  return arr.reduce(function(ret, item) {
    if ( parseInt(item._id) >= parseInt(id) ) {
      ret = ret.concat(item._id);
    }
    return ret;
  }, []);
}

console.log(getChildIdsInAnyOrder(data, '1'));
console.log(getChildIdsInAnyOrder(data, '2'));
console.log(getChildIdsInAnyOrder(data, '3'));
console.log(getChildIdsInAnyOrder(data, '4'));
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>

首先,您需要一个函数来从与搜索 ID 匹配的对象中获取 topLevelId

function getTLID(searchId) {
  return data.filter(function(el) {
    return el._id === searchId;
  })[0].topLevelId;
}

With reduce:将每个对象的 _id 添加到具有该搜索 ID 的返回数组中或者具有搜索 ID [=36] =]or 有一个 parentId 大于或等于搜索 id,使用 map 来获取 _ids.

function getIdArray(searchId) {
  var tlid = getTLID(searchId);
  return data.reduce(function (p, c) {
    var matchSearchId = +c.parentId >= +searchId || c._id === searchId;
    if (c.topLevelId === tlid && matchSearchId) p.push(c._id);
    return p;
  }, []).sort();
}

getIdArray('1') // [ "1", "2", "3", "4" ]
getIdArray('2') // [ "2", "3", "4" ]
getIdArray('3') // [ "3", "4" ]
getIdArray('4') // [ "4" ]

DEMO

如果您不喜欢 reduce,也许可以使用 filter and map

function getIdArray(searchId) {
  var tlid = getTLID(searchId);
  return data.filter(function(el) {
    var matchSearchId = +el.parentId >= +searchId || el._id === searchId;
    return el.topLevelId === tlid && matchSearchId;
  }).map(function(el) {
    return el._id;
  }).sort();
}

DEMO

您可以尝试这样的操作:

代码

JSFiddle

var data = [{
  "_id": "1",
  "parentId": "thisPostId",
  "topLevelId": "1",
  "text": "<p>comment</p>",
}, {
  "_id": "2",
  "parentId": "1",
  "topLevelId": "1",
  "text": "<p>reply to comment</p>",
}, {
  "_id": "3",
  "parentId": "2",
  "topLevelId": "1",
  "text": "<p>reply to reply to comment</p>",
}, {
  "_id": "4",
  "parentId": "3",
  "topLevelId": "1",
  "text": "<p>reply to reply to reply to comment</p>",
}];

function getDependentList(id) {
  var retList = [];

  data.forEach(function(item) {
    if (item.parentId == id)
      retList.push(item["_id"]);
  });

  if (retList.length > 0) {
    retList.forEach(function(item) {
      retList = retList.concat(getDependentList(item).slice(0));
    });
  }

  return retList;
}

function getRemoveList() {
  var id = document.getElementById("txtInput").value;
  var removeList = [];
  removeList.push(id);
  removeList = removeList.concat(getDependentList(id))
  console.log(removeList);
}
<input type="text" id="txtInput">
<button onclick="getRemoveList()">get Lists</button>

这是一篇使用递归的相当冗长的文章,

function getIDs(arr, id) {
arr = arr || data;
var ret = [];
for (var i = 0; i < arr.length; i++) {
    var item = arr[i];
    if (item.parentId == id || item._id == id) {
        if (ret.indexOf(item._id) < 0) {
            ret.push(item._id);
            var newret = []
            for (var x = 0; x < arr.length; x++) {
                if (x != i) newret.push(arr[x]);
            }
            var children = getIDs(newret, item._id);
            if (children.length > 0) {
                for (var j = 0; j < children.length; j++) {
                    if (!(ret.indexOf(children[j]) >= 0)) { ret.push(children[j]); }
                }
            }
        }

    }
}
return ret;

}

它的工作原理是获取所需父项的 ID,然后获取其子项的 ID,以及其子项的子项,它可以整天这样做......

这是一个带有临时 object 和递归调用 ID 的提案。

临时 object o 包含所有 ID 及其 childrens

{
    "1": ["2"],
    "2": ["3"],
    "3": ["4"],
    "thisPostId": ["1"]
}

构建此 object 后,获取查找的 ID 并检查 object 是否包含 属性。虽然所有 peoperty 都是数组,但可以遍历 go() 并获取所有 id 以进行收集。如果还有一个child,则递归迭代

var data = [{ "_id": "1", "parentId": "thisPostId", "topLevelId": "1", "text": "<p>comment</p>", }, { "_id": "2", "parentId": "1", "topLevelId": "1", "text": "<p>reply to comment</p>", }, { "_id": "3", "parentId": "2", "topLevelId": "1", "text": "<p>reply to reply to comment</p>", }, { "_id": "4", "parentId": "3", "topLevelId": "1", "text": "<p>reply to reply to reply to comment</p>", }];

function getConnected(s) {
    function go(a) { r.push(a); o[a] && o[a].forEach(go); }

    var o = data.reduce(function (r, a) {
            r[a.parentId] = r[a.parentId] || [];
            r[a.parentId].push(a._id);
            return r;                
        }, {}),
        r = [s];

    o[s] && o[s].forEach(go);
    return r;
}

for (var i = 1; i <= 4; i++) {
    document.write('"' + i + '": ' + JSON.stringify(getConnected(i.toString())) + '<br>');
}

在 OP 的评论中,您说您正在使用 meteorjs 并且您似乎想要级联删除文档。 Meteorjs hooks 轻松实现:

var idToRemove;
Coll.remove({ _id: idToRemove }, callback);

// what to do after removing a Coll document
Coll.after.remove(function (userId, doc) {
    Coll.remove({ parentId: doc._id });
});

您需要先安装 collection-hooks 包。