获取父元素及其所有子元素的数组

时间:2016-01-11 10:51:32

标签: javascript arrays underscore.js lodash

假设我有这种数据......

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的帮助都将受到赞赏,,,

谢谢你......

8 个答案:

答案 0 :(得分:3)

这是使用本机patoolib.extract_archive(my_file, outdir="/root/tree/def")方法的另一种解释,只将子元素添加到返回的数组中。

  

编辑,没有正确阅读问题,现在将返回当前ID和所有孩子。

&#13;
&#13;
import shutil, os, patoolib, fnmatch, glob

def unrar():
    for my_file in glob.glob('/root/tree/down/*'):
        if fnmatch.fnmatch(my_file, '*.rar'):
            patoolib.extract_archive(
                my_file, outdir="/root/tree/def")

unrar()
&#13;
Array.prototype.reduce
&#13;
&#13;
&#13;

  

任何订单,不确定为什么必要的想法。

&#13;
&#13;
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') );
&#13;
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

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

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

使用reduce:将每个对象的_id添加到返回的数组中,该数组的搜索ID为的搜索ID为如果parentId大于或等于搜索ID,则使用map来抓取_id

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,可能会使用filtermap

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

答案 2 :(得分:1)

这是一个使用递归的相当冗长的

phase_ids

}

它的工作原理是获取所需父级的ID,然后获取其子级的ID以及其子级的子级,它可以整天执行此操作...

答案 3 :(得分:0)

  

首先,您需要获取已提及_id的项目的索引,如果array中存在项目,则您可以使用array.splice删除n来自提到的索引的元素。要从deleted节点获取项目,数组的deepcopy存储在temperory变量中。

     

splice()方法通过删除现有元素和/或添加新元素来更改数组的内容。

您可以使用data.length - index

计算删除计数

&#13;
&#13;
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);
}
&#13;
&#13;
&#13;

Fiddle here

答案 4 :(得分:0)

尝试:

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;
}

答案 5 :(得分:0)

您可以尝试这样的事情:

代码

JSFiddle

&#13;
&#13;
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);
}
&#13;
<input type="text" id="txtInput">
<button onclick="getRemoveList()">get Lists</button>
&#13;
&#13;
&#13;

答案 6 :(得分:0)

这是一个带有临时对象和递归调用id的提案。

临时对象o包含所有ID及其子级

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

构建此对象后,将获取查找的ID,并检查该对象是否包含该属性。虽然所有peopertys都是数组,但可以迭代go()并获取所有id以进行收集。如果有另一个孩子,则递归迭代正在进行。

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>');
}

答案 7 :(得分:0)

在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软件包。