使用lodash.js搜索所有json元素

4

朋友们,我有一个JSON对象:

  var companies= [
    { id: 1, name: "Test Company", admin: "Test Admin" },
    { id: 2, name: "Another Company", admin: "Test Admin", country: 'Spain' },
    { id: 3, name: "New Company", admin: "Admin 4" },
    { id: 4, name: "Free Company", admin: "Jhon Miller", city: 'New York' }
];

我正在编写一个函数,用于返回新的JSON对象,其中包含我作为参数传递的元素(filter)。我制作了一个简单的

   function searchBooks(companies,filter){
    var result;
      if (typeof filter=== "undefined" ||  filter.length==0) {
          result = companies;
      } else {
        result = _.filter(companies, function (c) {
         return _.includes(_.lowerCase(c.name),_.lowerCase(filter));
       });
     }
 }

使用我的函数,我只能按名称过滤。我的问题是:如何按名称、管理员、国家和城市进行过滤,而不是按ID进行过滤?例如,如果您在变量中传递4,则应返回:
{ id: 3, name: "New Company", admin: "Admin 4" }
或者如果我搜索iLl,应该返回:
{ id: 4, name: "Free Company", admin: "Jhon Miller", city: 'New York' }
谢谢

这不是JSON,而是一个对象数组。JSON是一种数据交换格式,其格式类似于JS的子集。字符串'[{"id":1},{"id":2}]'是以JSON格式格式化的数据,可以被解析为JS数组:[{id: 1}, {id: 2}]。这可能看起来像是语义上的区别,但它是一个重要的区别。 - Useless Code
3个回答

6
下面的搜索功能利用 filter()text 搜索中获取匹配的对象。为了确定一个对象是否与搜索的 text 匹配,我们使用 some() 对集合中每个对象的所有值进行比较。some() 方法会将对象中的每个值以小写形式与搜索的 text 的小写形式使用 includes() 进行比较。
请注意,我使用了 toLower() 而不是 lowerCase(),因为后者将字符串转换为由单词分隔的小写格式,而前者完全将整个字符串转换为小写格式,不考虑字符串的大小写格式 -- 根据您的要求,您可以选择切换它。 更新:我添加了一个排除参数作为一种方式,省略()在测试从搜索的文本中的对象值时忽略某些属性。
function searchByText(collection, text, exclude) {
  text = _.toLower(text);
  return _.filter(collection, function(object) {
    return _(object).omit(exclude).some(function(string) {
      return _(string).toLower().includes(text);
    });
  });
}
console.log(searchByText(companies, '4'));
console.log(searchByText(companies, 'iLl'));
console.log(searchByText(companies, '4', ['id']));

var companies = [{
    id: 1,
    name: "Test Company",
    admin: "Test Admin"
  },
  {
    id: 2,
    name: "Another Company",
    admin: "Test Admin",
    country: 'Spain'
  },
  {
    id: 3,
    name: "New Company",
    admin: "Admin 4"
  },
  {
    id: 4,
    name: "Free Company",
    admin: "Jhon Miller",
    city: 'New York'
  }
];

function searchByText(collection, text, exclude) {
  text = _.toLower(text);
  return _.filter(collection, function(object) {
    return _(object).omit(exclude).some(function(string) {
      return _(string).toLower().includes(text);
    });
  });
}

console.log(searchByText(companies, '4'));
console.log(searchByText(companies, 'iLl'));
console.log(searchByText(companies, '4', ['id']));
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

这是上面解决方案的组合版本,使用partial()flow()
function searchByText(collection, text, exclude) {
  return _.filter(collection, _.flow(
    _.partial(_.omit, _, exclude),
    _.partial(
      _.some, _,
      _.flow(_.toLower, _.partial(_.includes, _, _.toLower(text), 0))
    )
  ));
}

console.log(searchByText(companies, '4'));
console.log(searchByText(companies, 'iLl'));
console.log(searchByText(companies, '4', ['id']));

var companies = [{
    id: 1,
    name: "Test Company",
    admin: "Test Admin"
  },
  {
    id: 2,
    name: "Another Company",
    admin: "Test Admin",
    country: 'Spain'
  },
  {
    id: 3,
    name: "New Company",
    admin: "Admin 4"
  },
  {
    id: 4,
    name: "Free Company",
    admin: "Jhon Miller",
    city: 'New York'
  }
];

function searchByText(collection, text, exclude) {
  return _.filter(collection, _.flow(
    _.partial(_.omit, _, exclude),
    _.partial(
      _.some, _,
      _.flow(_.toLower, _.partial(_.includes, _, _.toLower(text), 0))
    )
  ));
}

console.log(searchByText(companies, '4'));
console.log(searchByText(companies, 'iLl'));
console.log(searchByText(companies, '4', ['id']));
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>


谢谢 @ryeballar。你的两个解决方案非常优雅,但我需要知道如何排除筛选器中的ID?因为如果我写4 show 2 registers and should show 1 only : { id: 3, name: "New Company", admin: "Admin 4" },它应该只显示1个。 - Vivianita21
谢谢!你的解决方案是100%有效的。 - Vivianita21

0

如何使用相同的方式搜索每个属性,指定您潜在的搜索关键字,请参见searchBooksSpecificProperties

或者,如果您总是想要搜索所有字段,可以使用_.keys()获取每个项目的键,参见searchBooks

var companies= [
    { id: 1, name: "Test Company", admin: "Test Admin" },
    { id: 2, name: "Another Company", admin: "Test Admin", country: 'Spain' },
    { id: 3, name: "New Company", admin: "Admin 4" },
    { id: 4, name: "Free Company", admin: "Jhon Miller", city: 'New York' }
];

function searchBooks(companies, filter){
  var result;
    if (typeof filter=== "undefined" ||  filter.length==0) {
        result = companies;
    } else {
      result = _.filter(companies, function (c) {
        var cProperties = _.keys(c);
        _.pull(cProperties, 'id');
        return _.find(cProperties, function(property) {
          if (c[property]) {
            return _.includes(_.lowerCase(c[property]),_.lowerCase(filter));
          }          
        });         
     });
   }
   return result;
 }

 console.log('searchBooks:');
 console.log(searchBooks(companies, 'Admin 4'))
 console.log(searchBooks(companies, 'York'))
 
function searchBooksSpecificProperties(properties, companies, filter){
  var searchSpecificProperties = _.isArray(properties);
  var result;
    if (typeof filter=== "undefined" ||  filter.length==0) {
        result = companies;
    } else {
      result = _.filter(companies, function (c) {
        var cProperties = searchSpecificProperties ? properties : _.keys(c);
        return _.find(cProperties, function(property) {
          if (c[property]) {
            return _.includes(_.lowerCase(c[property]),_.lowerCase(filter));
          }          
        });         
     });
   }
   return result;
 }
 console.log('searchBooksSpecificProperties:');
 console.log(searchBooksSpecificProperties(['name', 'admin'], companies, 'Admin 4'))
 console.log(searchBooksSpecificProperties(['name', 'admin'], companies, 'York'))
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>


谢谢@Apostolidis,但我如何使用仅接收2个参数的函数来实现此操作?而不是使用属性。 - Vivianita21
我修改了我的答案,添加了两个不同的函数。你可以看到searchBooks()searchBooksSpecificProperties() - Apostolidis

0

Object.keys() 是关键 ;)

试试这个:

var companies= [
    { id: 1, name: "Test Company", admin: "Test Admin" },
    { id: 2, name: "Another Company", admin: "Test Admin", country: 'Spain' },
    { id: 3, name: "New Company", admin: "Admin 4" },
    { id: 4, name: "Free Company", admin: "Jhon Miller", city: 'New York' }
];

function searchBooks(filter){
    var result;
      if (typeof filter=== "undefined" ||  filter.length==0) {
          result = companies;
      } else {
        result = _.filter(companies, function (c) {

         // This part will transform every property value in a single string.
         var searchIn = Object.keys(c).reduce(function(res, val) { return (val !== 'id')?res+c[val]:res }, '');
         return _.includes(_.lowerCase(searchIn),_.lowerCase(filter));
       });
     }
     console.log(result)
 }
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
<input type="text" onKeyUp="searchBooks(this.value)">


谢谢@SteevePitis,你的解决方案是有效的,但我需要知道如何排除ID进行过滤,因为如果我写4来显示2个记录,应该只显示1个。 - Vivianita21
如果您想仅显示第一个结果,则只需返回result[0] - Steeve Pitis
我知道这个,但我的问题是在搜索时是否可以排除ID。想象一下其他记录有“4”,应该返回2个记录而不是3个。谢谢。 - Vivianita21
我不太确定你想要什么。你想显示除了ID为“X”(例如2)的所有结果吗? - Steeve Pitis
哦,我想我明白了,你想从搜索列表中删除“id”键? - Steeve Pitis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接