如何使用多个条件或索引查询数据?

时间:2016-06-20 01:38:54

标签: firebase firebase-realtime-database nosql

我正在尝试为Firebase应用程序设计高性能的NoSQL架构,但我如何查询具有唯一标记的多个检查点

请考虑以下规则:

  • Tiers可以有多个标签
  • 标签可以有多个检查点
  • 标记键(名称)对于每个层都是唯一的
  • 检查点可以有多个标签,但每层只有一个标签

这是我到目前为止所拥有的:

{ 
    "tiers": {
        "1": {
            "web": true,
            "android": true
        },
        "2": {
            "basics": true,
            "angular2": true,
            "aurelia": true
        },
        "3": {
            "basics": true,
            "components": true
        }
    },
    "tags" : {
        "1": {
            "web": {
                "name": "Web Development",
                "children": {
                    "front-end": true,
                    "angular2": true,
                    "aurelia": true
                }
            },
            "android": {
                "name": "Android Development",
                "children": {
                    "front-end": true
                }
            }            
        },
        "2": {
            "front-end": {
                "name": "Basics",
                "parents": {
                    "web": true,
                    "android": true
                },
                "children": {
                    "angular2": true,
                    "aurelia": true,
                    "android-studio": true
                }                
            }                           
        },
        "3": {
            "angular2": {
                "name": "Angular 2.x",
                "parents": {...},
                "children": {...}
            },
            "aurelia": {
                "name": "Aurelia 1.x"
            }   
        }        
    },
    "checkpoints": {
        "<randomKey>" : {
            "name": "Angular 2 Quick Start",
            "tags": {
                "1": "web",
                "2": "front-end",
                "3": "angular2"
            }
        }
    }
}

现在,我可以在第1层web标记下查询所有检查点:

ref.orderByChild('tags/1').equalTo("web").once('value', snap => console.log(snap.val()));

但由于您只能定义一个indexOn规则,因此未对其进行优化。至少如果我可以设置indexOn规则,我至少可以过滤掉大部分检查点,然后在我的代码中过滤掉其余部分。

如何根据多个tagstiers

高效查询检查点?

最终,我需要使用checkpoints"tags": {"1": "web" AND "2": "front-end"}进行查询,但我无法确定如何有效执行。我正在考虑使用复合键执行另一个表(例如,每个tier/tag包含对所有子checkpoints的引用),但这会导致我要求在每个层中添加和删除引用。

必须有更好的方法。

1 个答案:

答案 0 :(得分:0)

我大大超过了解决方案 - 我最终:

  1. 从等式中删除Tier
  2. 在每个标记中添加与
  3. 相关的每个检查点
  4. 查询与所选标签相关的所有检查点,并删除未在所选标签中显示的检查点
  5. 这是我的新架构:

    allTags = [
      {"abc": true, "def": true, "hij": true},
      {"abc": true, "def": true}
    ];
    
    tags: [
      { "0": [
        {"software-development": {name: "Software Development", checkpoints: [ {"abc": true}, {"def": true}, {"hij": true}]}}
      ]},
      {"1": [
        {"web": {name: "Web", checkpoints: [ {"abc": true}, {"def": true}]}},
        {"android": {name: "Android", checkpoints: [{"hij": true}]}}  
      ]}
    ];
    
    checkpoints: [
      {"abc": { name: "Angular2 Quick Start"}},
      {"def": { name: "Building global directives in Angular2"}},
      {"hij": { name: "Android Quick Start"}},
    ];
    

    创建新的检查点:

    public createCheckpoint(tags: any[], checkpoint: any) {
      // push checkpoint
      let checkpointRef = this.firebase.child('test/checkpoints');
      let checkpointKey = checkpointRef.push(checkpoint).key(); // might have to do separate call
    
      // Add checkpoint under each related tag
      tags.forEach(tag => {
        let tagRef = this.firebase.child('test/tags/' + tag.tier + '/' + tag.key + '/checkpoints/' + checkpointKey);
        tagRef.set(true)
      });
    }
    

    根据所选标签检索所有检查点:

    public getCheckpointss(tags: any[]) {
      // tag.tier, tag.key
      let checkpointKeysToGet: string[] = [];
      tags.forEach(tag => {
        let ref = this.firebase.child('test/tags/' + tag.tier + '/' + tag.key + '/checkpoints');
        ref.once('value', snap => {
          let tagKeys:string[] = this.convertToArray(snap.val());
          if (checkpointKeysToGet.length == 0){
            checkpointKeysToGet = checkpointKeysToGet.concat(tagKeys);
          }
          else {
            checkpointKeysToGet.forEach(existingTagKey => {
              let tagKeysInBothTiers = tagKeys.filter(tagKey => {
                return checkpointKeysToGet.includes(tagKey, 0)
              });
              checkpointKeysToGet = tagKeysInBothTiers;
              console.log(checkpointKeysToGet);
            });
    
          }
        });
      });
    }
    

    只要您提出解决方案,我们欢迎所有有效的批评:)