简体   繁体   中英

get array of parent and all of its child

suppose I have this kind of data...

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>",
}]

I need to remove a comment and all of its child...

if comment to remove is _id:1 ,, then I need an array of ["1","2","3","4"] ,,, then i can run Coll.remove({_id:{$in:["1","2","3","4"]}}, callback);

if comment to remove is _id:2 ,, then I need an array of ["2","3","4"]

if comment to remove is _id:3 ,, then I need an array of ["3","4"]

if comment to remove is _id:4 ,, then I need an array of ["4"]

I tried this (with no idea)...

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

and not working...

any help with javascript/lodash/underscore will be appreciated,,,

thank You...

Here is another interpretation using the native Array.prototype.reduce method to only add the child elements to the returned array.

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> 

First you need a function to get the topLevelId from the object with that matches the search id:

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

With reduce : add the _id of each object to the returned array that has that search id and either have the search id or have a parentId greater or equal to the search id, the use map to grab the _id s.

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

If you don't like reduce , perhaps using 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

This is a rather lengthy one using recursion,

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;

}

It works by getting the id of the desired parent, then getting the ids of its children, and its children's children, it could do this all day ...

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.

You can calculate the delete count using 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

TRY THIS:

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

You can try something like this:

Code

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> 

This is a proposal with a temporary object and a recursive call for the ids.

The temporary object o contains all ids and their childrens

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

After this object is build, the id for the look up is taken and checked if the object contains the property. While all peopertys are arrays, it is possible to iterate over go() and get all id for collecting. If there is another child, the recursive iteration is going on.

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

In the OP's comments, you said you're using meteorjs and you seem to want to cascade delete a document. Meteorjs hooks allow this easily:

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

You need to install the collection-hooks package first.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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