2

I am new to Gun. I have existing code that very effectively reduces an array of objects based on a pattern. I am thinking I should tweak this to run in the context of Gun's .map and return undefined for non-matches. I think I will also have to provide two arguments, one of which is the where clause and the other the properties I want shown on returned objects. I also presume that if I use .on future matches will automagically get spit out! Am I on the right path?

const match = (object,key,value) => {
  const type = typeof(value);
  if(value && type==="object") {
     return Object.keys(value).every(childkey => 
           match(object[key],childkey,value[childkey]));
  if(type==="function") return value(object[key]);
  return object[key]===value; 
}
const reduce = (objects,where) => {
  const keys = Object.keys(where);
  return objects.reduce((accumulator,current) => {
    if(keys.every(key => match(current,key,where[key]))) {
      accumulator.push(current);
    }
    return accumulator;
  },[]);
}

let rows = reduce([{name: "Joe",address:{city: "Seattle"},age:25},
    {name: "Mary",address:{city: "Seattle"},age:16},
    {name: "Joe",address:{city: "New York"},age:20}],
    {name: () => true,
     address: {city: "Seattle"}, 
     age: (age) => age > 10});

// results in [{name: "Joe",address:{city: "Seattle"},age:25}, {name: "Mary",address:{city: "Seattle"},age:16}]

Further exploration of this resulted in the code below, which is stylistically different, but conforms to the immediate responsive nature of Gun. However, it is unclear how to deal with nested objects. The code below only works for primitives.

const match = (object,key,value) => {
    const type = typeof(value);
    if(!object || typeof(object)!=="object") return false; 
    if(value && type==="object") {
        const child = gun.get(object[key]["#"]);
        for(let key in value) {
            const value = {};
            child.get(key).val(v => value[key] = v,{wait:0});
            if(!match(value,key,value[key])) return;
        }
    }
    if(type==="function") return value(object[key]);
    return object[key]===value; 
}

const gun = Gun(["http://localhost:8080/gun"]),
        users = [{name: "Joe",address:{city: "Seattle"},age:25},
        {address:{city: "Seattle"},age:25},
        {name: "Mary",address:{city: "Seattle"},age:16},
        {name: "Joe",address:{city: "New York"},age:20}];

//gun.get("users").map().put(null);

for(let user of users) {
    const object = gun.get(user.name).put(user);
    gun.get("users").set(object);
}

gun.get("users").map(user => { 
    const pattern = {name: (value) => value!=null, age: (age) => age > 20}; //, address: {city: "Seattle"}
    for(let key in pattern) {
        if(!match(user,key,pattern[key])) return;
    }
    return user;
}).on(data => console.log(data));
4

2 回答 2

1

是的。GUN 的.map 方法比看起来的要多。

说我们有var users = gun.get('users')。我们可以做的:

  • users.map()没有回调的行为就像 aforEach因为默认回调是按原样返回数据。
  • users.map(user => user.age * 2)通过回调,它可以让您转换数据,就像您对 a 的期望一样map,除了:
  • users.map(function(){ return })如果您返回undefined,它将filter输出该记录。

警告:截至目前,.map(transform)功能目前是实验性的,我有它的错误。请尝试并报告您发现的任何内容。

现在我们可以将它与其他一些方法结合起来,以获得一些很酷的行为:

  • users.map().on(cb)将获得当前和未来的用户,因为他们被添加到表中,并收到有关每个用户更新的通知。
  • users.map().val(cb)将获得当前和未来的用户,因为他们被添加到表中,但每个人只获得一次。
  • users.val().map().on(cb)仅获取当前用户(而不是未来用户),但获取这些用户的更新。
  • users.val().map().val(cb)只获取当前用户(而不是未来用户),并且只获取一次。

所以,是的,你在正确的轨道上。例如,我在枪芯中有一个测试可以做到这一点:

list.map(user => user.age === 27? user.name + "thezombie" : u).on(function(data){
    // verify
});
list.set({name: 'alice', age: 27});
list.set({name: 'bob', age: 27});
list.set({name: 'carl', age: 29});
list.set({name: 'dave', age: 25});

这将创建一个实时map过滤结果并在本地(仅查看)转换数据。

将来,这就是 SQL 和 MongoDB Mango 查询扩展将如何为 gun 工作。

注意:GUN 仅在对象/节点上加载您请求的属性,因此它具有带宽效率。如果我们这样做users.map().get('age'),它只会加载每个用户的年龄值,没有别的。

所以在内部,您可以进行一些有效的检查,如果您的所有条件都匹配,则仅 /then/ 加载整个对象。此外,还有其他两个选项:(1)您可以使用 gun 的内存版本来创建服务器端请求-响应模式,因此您可以进行高效的服务器端过滤/查询。(2) 如果您成为适配器开发人员并学习简单的电线规范,然后编写您自己的自定义查询语言扩展!

还要别的吗?打我!非常乐意回答。

编辑:我在评论中的回复,评论显然不能有代码。下面是如何“构建”更复杂查询的伪代码,类似于 SQL/Mango 查询扩展的工作方式:

多值和嵌套值匹配可以以此为基础“构建”,但是是的,你是对的,直到我们有 SQL/Mango 查询示例,没有简单/直接的“开箱即用”示例. 这是伪代码,但应该可以理解:

```

Gun.chain.match = function(query, cb){
  var gun = this;
  var fields = Object.keys(query);
  var check = {};
  fields.forEach(function(field){
    check[field] = true;
    gun.get(field).val(function(val){
       if(val !== query[field]){ return }
       check[field] = false;
       //all checks done?
       cb(results)
    });
  });
  return gun;
}

```

于 2017-05-22T22:21:43.053 回答
0

解决方案,诀窍是使用map而不是val

Gun.chain.match = function(pattern,cb) {
            let node = this,
                passed = true,
                keys = Object.keys(pattern);
            keys.every(key => {
                const test = pattern[key],
                    type = typeof(test);
                if(test && type==="object") {
                    node.get(key).match(test);
                } else if(type==="function") {
                    node.get(key).map(value => { 
                        if(test(value[key])) { 
                            return value; 
                        } else { 
                            passed = false; 
                        } 
                    });
                } else {
                    node.get(key).map(value => { 
                        if(value[key]===test) { 
                            return value; 
                        } else { 
                            passed = false; 
                        } 
                    });
                }
                return passed;
            });
            if(passed && cb) this.val(value => cb(value))
            return this;
        }
        const gun = new Gun();
        gun.get("Joe").put({name:"Joe",address:{city:"Seattle"},age:20});
        gun.get("Joe").match({age: value => value > 15,address:{ city: "Seattle"}},value => console.log("cb1",value));
于 2017-05-25T03:29:26.107 回答