使用部分匹配查找另一个对象的对象

3

我有以下数据:

 let Collection = [{
    id: '1',
    uid: 'u1',
    rci: 'r1',
    name: 'ClientName'
  }, {
    uid: 'u2',
    name: 'ClientName 2'
  }, {
    rci: 'r3',
    name: 'ClientName 3'
  }]

id、uid和rci是三个不同的id属性(来自可怕的数据库合并结果)。

每个客户端:

  • 至少拥有这三个属性中的一个
  • 可能拥有所有三个id

现在问题来了: 我需要使用类似于以下对象的方式搜索此集合:

search: {
    id: undefined,
    uid: 'u3',
    rci: 'r3'
}

这段文字的意思是,该集合中的第三个条目与其它条目不同,因为它们的属性匹配。

显然,有一个解决方案:

let match;

let test = Collection.forEach(item => {
  Object.keys(search).forEach(key => {
    console.log('iteration')
    if(item[key] && item[key] === search[key]) {
        match = item
    }
  })
}) 

但我正在寻找更加优雅的解决方案。我还在使用underscorejs。

注意:这是不可变的.js集合/映射/列表的POJO版本。如果可以通过Immutable.js实现同样的功能,那就太好了 :)


"if(item[key] && item[key] === search[key]) {"* 您的搜索值不能为零吗?(或任何其他假值?) - T.J. Crowder
@T.J.Crowder 通常情况下,ID不可能为零。但是,如果数据库有问题,谁知道呢... - SparK
还没有检查它是否符合您的要求,但Underscore有一个IsMatch函数:http://underscorejs.org/#isMatch - Me.Name
@Me.Name:不,因为他的例子 search 不会匹配第三个条目,因为第三个条目只有 rci 而没有 uidid - T.J. Crowder
2个回答

1
在纯Javascript中,您可以使用Array#filter()Array#some()

function find(array, search) {
    var s = {};
    Object.keys(search).forEach(function (k) {
        if (typeof search[k] !== 'undefined') {
            s[k] = search[k];
        }
    });
    return array.filter(function (a) {
        return Object.keys(s).some(function (k) {
            return s[k] === a[k];
        });
    });
}

var collection = [{ id: '1', uid: 'u1', rci: 'r1', name: 'ClientName' }, { uid: 'u2', name: 'ClientName 2' }, { rci: 'r3', name: 'ClientName 3' }],
    result = find(collection, { id: undefined, uid: 'u3', rci: 'r3' });

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');


1
如果我理解你的问题正确,搜索应该找到与search对象上的任何非undefined键/值对匹配的内容(而不是全部匹配)。
如果是这样,你可以通过一次性确定这些键并在找到匹配项后停止循环来使其更加高效:
let keys = Object.keys(search).filter(key => search[key] !== undefined);
let match = _.find(Collection, item => keys.some(key => item[key] === search[key]));

自ES2015(又名ES6)或使用Array#find的shim之后,将不再需要Underscore:
let keys = Object.keys(search).filter(key => search[key] !== undefined);
let match = Collection.find(item => keys.some(key => item[key] === search[key]));

我们不需要你提到的item[key] &&,因为在开始搜索之前,我们会过滤掉值为undefined的键,所以如果该项没有键,item[key]就不会与search[key]进行===匹配。

这里有一个实时示例,使用Babel的REPL和您的示例数据,展示了ES2015版本。


关于search[key] !== undefinedtypeof search[k] !== 'undefined'之间的区别,我有一个简短的问题。在这种情况下哪个更好? - Nina Scholz
1
@NinaScholz:我认为在今天的世界中这并不重要。undefined全局现在是只读的。很久以前,一个窗口中的undefined与另一个窗口中的undefined不相等存在问题。然而,仍然(遗憾地)有可能掩盖符号undefined,因此,如果您正在编写一个通用库,该库可能在您无法控制的范围内执行,某人可能已经做了一些疯狂的事情,例如var undefined = 42,那么您可能需要防范这种情况。*(续)* - T.J. Crowder
1
通常在这种情况下,您已经有了一个作用域函数(因此您可以拥有特定于库的私有全局变量),这提供了一种简单的方法来处理该防御:(function(undefined) { ... })(); 我总是确保我可以信任 undefined,所以我不必使用更长的 typeof 检查。 - T.J. Crowder

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