如何通过多个条件或索引查询数据?

How do you query data by with multiple conditions or indexes?

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

考虑以下规则:

这是我目前的情况:

{ 
    "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 有效地查询我的检查点?

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

一定有更好的方法。

我把解决方案复杂化了很多 - 结果是:

  1. 一起从等式中删除 Tier
  2. 在每个与之相关的标签中添加每个检查点
  3. 查询与每个选定标签相关的所有检查点并删除未出现在每个选定标签中的检查点

这是我的新架构:

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

      }
    });
  });
}

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