简体   繁体   English

Lodash - 搜索项目然后删除 object 中不匹配的其他项目

[英]Lodash - search for item then remove other items that does not match in the object

I have this multidimensional array and I am doing a search and extracting them.我有这个多维数组,我正在搜索并提取它们。

This is what my object looks like:这是我的 object 的样子:

[
   {
      "id":1,
      "name":"Hot Drinks",
      "created_at":null,
      "updated_at":null,
      "menus":[
         {
            "id":1,
            "name":"Brewed Coffee",
            "price":"90.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":2,
            "name":"Drip Coffee",
            "price":"100.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":3,
            "name":"Cappuccino",
            "price":"100.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":4,
            "name":"Caffe Latte",
            "price":"100.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":5,
            "name":"Caffe Mocha",
            "price":"120.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         }
      ]
   },
   {
      "id":2,
      "name":"Cold Drinks",
      "created_at":null,
      "updated_at":null,
      "menus":[
         {
            "id":6,
            "name":"Iced Coffee",
            "price":"110.00",
            "category_id":2,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":7,
            "name":"Iced Latte",
            "price":"120.00",
            "category_id":2,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":8,
            "name":"Iced Mocha",
            "price":"140.00",
            "category_id":2,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         }
      ]
   },
   {
      "id":3,
      "name":"Beverages",
      "created_at":null,
      "updated_at":null,
      "menus":[
         
      ]
   },
   {
      "id":4,
      "name":"Starters",
      "created_at":null,
      "updated_at":null,
      "menus":[
         {
            "id":9,
            "name":"Sizzling Sisig",
            "price":"129.00",
            "category_id":4,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":10,
            "name":"Lumpia Shanghai",
            "price":"149.00",
            "category_id":4,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":11,
            "name":"Pork & Shrimp Siomai",
            "price":"169.00",
            "category_id":4,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":12,
            "name":"Spicy Tok Ramen",
            "price":"159.00",
            "category_id":4,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":14,
            "name":"Humba Rice Meal",
            "price":"110.00",
            "category_id":4,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":15,
            "name":"Siomai Rice Meal",
            "price":"110.00",
            "category_id":4,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":16,
            "name":"Sisig Rice Meal",
            "price":"110.00",
            "category_id":4,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":18,
            "name":"Suman (Pack of 6)",
            "price":"110.00",
            "category_id":4,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         }
      ]
   },
   {
      "id":5,
      "name":"Rice Meals",
      "created_at":null,
      "updated_at":null,
      "menus":[
         {
            "id":13,
            "name":"Humba Rice Meal",
            "price":"110.00",
            "category_id":5,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":17,
            "name":"Suman & Hot Choco",
            "price":"140.00",
            "category_id":5,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         }
      ]
   },
   {
      "id":6,
      "name":"Desserts",
      "created_at":null,
      "updated_at":null,
      "menus":[
         
      ]
   }
]

This is how i do a search on the menus object.这就是我在菜单 object 上进行搜索的方式。

_.filter(this.originalMenus, {menus: [{name: _this.search}] });

The problem with this code is that if I searched "Brewed Coffee", it gets the entire menus object instead of just the menus object with just the "Brewed Coffee" that matches.这段代码的问题是,如果我搜索“Brewed Coffee”,它会得到整个menus object,而不仅仅是menus object,其中只有匹配的“Brewed Coffee”。 So the returned result is like this, which is wrong:所以返回的结果是这样的,这是错误的:

[
   {
      "id":1,
      "name":"Hot Drinks",
      "created_at":null,
      "updated_at":null,
      "menus":[
         {
            "id":1,
            "name":"Brewed Coffee",
            "price":"90.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":2,
            "name":"Drip Coffee",
            "price":"100.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":3,
            "name":"Cappuccino",
            "price":"100.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":4,
            "name":"Caffe Latte",
            "price":"100.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
         {
            "id":5,
            "name":"Caffe Mocha",
            "price":"120.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         }
      ]
   }
]

As you can see it included the other menu items which the Brewed Coffee belongs.如您所见,它包含了 Brewed Coffee 所属的其他菜单项。

How can I extract it that it looks like this:我怎样才能提取它看起来像这样:

[
   {
      "id":1,
      "name":"Hot Drinks",
      "created_at":null,
      "updated_at":null,
      "menus":[
         {
            "id":1,
            "name":"Brewed Coffee",
            "price":"90.00",
            "category_id":1,
            "deleted_at":null,
            "created_at":null,
            "updated_at":null
         },
      ]
   }
]

Apologies if I didn't explain it properly.抱歉,如果我没有正确解释它。

Another help if you can include it in your answer is that how can I do a search that partially matches the search, something like LIKE %search% in MySQL.如果您可以将其包含在您的答案中,另一个帮助是我如何进行与搜索部分匹配的搜索,例如 MySQL 中的LIKE %search%

Your help is greatly appreciated.非常感谢您的帮助。 Thank you.谢谢你。

When use like this像这样使用的时候

_.filter(this.originalMenus, {menus: [{name: _this.search}] });

It will return all the object inside this.originalMenus if {menus: [{name: _this.search}] } gets passed.如果{menus: [{name: _this.search}] }被通过,它将返回 this.originalMenus 内的所有this.originalMenus

Basicaly it's filtering this.originalMenus when {menus: [{name: _this.search}] } gets passed, it's not filtering inner menus, inner menus are used as condition to filter the menu.基本上它在{menus: [{name: _this.search}] }被通过时过滤this.originalMenus ,它不是过滤内部菜单,内部菜单用作过滤菜单的条件。

so you might need to create a own filtering logic所以您可能需要创建自己的过滤逻辑

EX:前任:

function filterCofee(search) {
  const filterdMenus = [];

  menus.forEach(menu => {
    // check if there's sub menus that we can filter.
    var filterdMenu = _.filter(menu.menus, { name: search });    

    // if there's matches, then we will add it a array, and return it.
    if (filterdMenu.length > 0) {
      filterdMenus.push({
        ...menu,
        menus: [...filterdMenu]
      });
    }
  });

  return filterdMenus;
}

filterCofee("Brewed Coffee")

demo演示


and if you want to use it like LIKE %search% , then replace the above filter with如果您想像LIKE %search%一样使用它,请将上面的过滤器替换为

// Here we are checking if the search text included in any of the name at any position.
var filterdMenu = _.filter(menu.menus, (m) => m.name.indexOf(search) >= 0);

demo演示

You may also consider simply using plain vanilla Javascript您也可以考虑简单地使用普通香草 Javascript

 const allMenus = [{ "id": 1, "name": "Hot Drinks", "created_at": null, "updated_at": null, "menus": [{ "id": 1, "name": "Brewed Coffee", "price": "90.00", "category_id": 1, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 2, "name": "Drip Coffee", "price": "100.00", "category_id": 1, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 3, "name": "Cappuccino", "price": "100.00", "category_id": 1, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 4, "name": "Caffe Latte", "price": "100.00", "category_id": 1, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 5, "name": "Caffe Mocha", "price": "120.00", "category_id": 1, "deleted_at": null, "created_at": null, "updated_at": null } ] }, { "id": 2, "name": "Cold Drinks", "created_at": null, "updated_at": null, "menus": [{ "id": 6, "name": "Iced Coffee", "price": "110.00", "category_id": 2, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 7, "name": "Iced Latte", "price": "120.00", "category_id": 2, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 8, "name": "Iced Mocha", "price": "140.00", "category_id": 2, "deleted_at": null, "created_at": null, "updated_at": null } ] }, { "id": 3, "name": "Beverages", "created_at": null, "updated_at": null, "menus": [ ] }, { "id": 4, "name": "Starters", "created_at": null, "updated_at": null, "menus": [{ "id": 9, "name": "Sizzling Sisig", "price": "129.00", "category_id": 4, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 10, "name": "Lumpia Shanghai", "price": "149.00", "category_id": 4, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 11, "name": "Pork & Shrimp Siomai", "price": "169.00", "category_id": 4, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 12, "name": "Spicy Tok Ramen", "price": "159.00", "category_id": 4, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 14, "name": "Humba Rice Meal", "price": "110.00", "category_id": 4, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 15, "name": "Siomai Rice Meal", "price": "110.00", "category_id": 4, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 16, "name": "Sisig Rice Meal", "price": "110.00", "category_id": 4, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 18, "name": "Suman (Pack of 6)", "price": "110.00", "category_id": 4, "deleted_at": null, "created_at": null, "updated_at": null } ] }, { "id": 5, "name": "Rice Meals", "created_at": null, "updated_at": null, "menus": [{ "id": 13, "name": "Humba Rice Meal", "price": "110.00", "category_id": 5, "deleted_at": null, "created_at": null, "updated_at": null }, { "id": 17, "name": "Suman & Hot Choco", "price": "140.00", "category_id": 5, "deleted_at": null, "created_at": null, "updated_at": null } ] }, { "id": 6, "name": "Desserts", "created_at": null, "updated_at": null, "menus": [ ] } ] const filterBy = (search) => allMenus.map( menu => ({...menu, menus: menu.menus.filter(({ name }) => name.includes(search)) }) ).filter(({menus}) => menus.length > 0) console.log(filterBy("Brewed Coffee"))

So _.filter is going to return true or false for every element in an array and return the array.所以_.filter将为数组中的每个元素返回 true 或 false 并返回数组。 Because you are filter your top level menus ("Hot Drinks", "Cold Drinks"), the whole thing will be return there if it matches your predicate.因为您正在过滤您的顶级菜单(“热饮”、“冷饮”),所以如果它与您的谓词匹配,则整个内容将返回那里。

You may be better off using the es6 .map function and passing in your own custom function to filter and map the object as you want it to. You may be better off using the es6 .map function and passing in your own custom function to filter and map the object as you want it to. The .map or .filter functions are also where you'd be able to do your own logic for partial matches like you were asking. .map.filter函数也是您可以为部分匹配执行自己的逻辑的地方,就像您要求的那样。

Otherwise you can do the following to essentially use lodash to do the filter, then use .map to remove the extra items from the menus array.否则,您可以执行以下操作以基本上使用 lodash 进行过滤,然后使用.mapmenus数组中删除额外的项目。

var filtered = _.filter(this.originalMenus, {menus: [{name: _this.search}] });
filtered.map(function(m,i){m.menus = _.filter(m.menus,{name: _this.search});

but I'd recommend something more along the lines of just using the .filter and .map functions like this但我会推荐更多类似这样的.filter.map函数

var filtered = originalMenus.filter((topMenu)=> 
    topMenu.menus.filter((sub)=>
        sub.name.toLowerCase().includes(search.toLowerCase())).length > 0)
    .map((m)=>
        {return {...m, ...{menus:m.menus.filter((f)=>f.name.toLowerCase().includes(search.toLowerCase()))}}}
    )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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