【问题标题】:Using map to reduce in Gun在 Gun 中使用 map 减少
【发布时间】:2017-05-22 21:04:56
【问题描述】:

我是枪新手。我现有的代码可以非常有效地减少基于模式的对象数组。我在想我应该调整它以在 Gun 的 .map 上下文中运行,并为不匹配返回 undefined 。我想我还必须提供两个参数,其中一个是 where 子句,另一个是我希望在返回的对象上显示的属性。我还假设如果我使用 .on 未来的比赛会自动吐出!我走对了吗?

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

// 结果 [{姓名:“乔”,地址:{城市:“西雅图”},年龄:25}, {姓名:“玛丽”,地址:{城市:“西雅图”},年龄:16}]

对此的进一步探索产生了以下代码,该代码在风格上有所不同,但符合 Gun 的即时响应特性。但是,目前还不清楚如何处理嵌套对象。下面的代码仅适用于原语。

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

【问题讨论】:

    标签: gun


    【解决方案1】:

    是的。 GUN 的 .map method 做的比看起来的要多。

    假设我们有var users = gun.get('users')。我们可以这样做:

    • 没有回调的users.map() 的作用类似于forEach,因为默认回调是按原样返回数据。
    • users.map(user => user.age * 2) 带有回调,它可以让您转换数据,就像您对 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) 如果您成为适配器开发人员并学习简单的电线规范,然后编写自己的自定义查询语言扩展!

    还有什么?打我!非常乐意回答。

    编辑:我在 cmets 的回复, cmets 显然不能有代码。下面是如何“构建”更复杂查询的伪代码,类似于 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;
    }
    

    ```

    【讨论】:

    • 好吧,事实证明,对原始值进行映射以使用模式进行过滤非常简单。挑战似乎是与嵌套对象匹配。
    • 多值和嵌套值匹配可以以此为基础“构建”,但是是的,你是对的,直到我们有 SQL/Mango 查询示例,没有简单的/立即“开箱即用”的示例。这是伪代码,但应该可以理解:``` Gun.chain.match = function(query, cb){ var gun = this; var fields = Object.keys(query);变量检查 = {}; fields.forEach(function(field){ check[field] = true; gun.get(field).val(function(val){ if(val !== query[field]){ return } check[field] = false ; //所有检查都完成了吗?cb() }); }); } ```
    【解决方案2】:

    解决方案,诀窍是使用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-02-12
      • 1970-01-01
      • 1970-01-01
      • 2013-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多