Firebase:如何从存在特定键的数据中检索记录?

Firebase: How do I retrieve records from my data for which a specific key exists?

我在 firebase 中有这样的数据:

"application": {
  "companies": {
    "firebase": {
      "creation": {
        "name": "Firebase Inc",
        "location": "USA"
      },

      "google": {
        "creattion": {
          "name": "Google Inc",
          "location": "USA"
        }
      }

      "facebook": {
      },

      "apple": {
      }
    }
  }
}

companies键下有几万条记录。我如何有效地执行以下查询?

如何只查询名字下有关键字 creation 的记录?

如何只查询名称下没有键 creation 的记录?

我还想对返回的结果集调用 .on('child_added'),这样我以后就可以只处理那些特定的记录。可能吗?

我会做的是设置一个条件来验证您的 xxx.firebaseio.com/Application/companies/______/creation 是否存在。在空白处,可以设置for循环遍历companies.Then的数组,可以创建两个angular.forEach的数组:一个包含那些有'creation'的公司,另一个元素不包含 'creation'.

的数组

希望对您有所帮助:)

编辑:
这个问题还有另一种方法,在这个线程中:
Angularfire: how to query the values of a specific key in an array?

编辑:不使用额外参数的更简单方法

查询

以下是无需使用额外参数即可执行此操作的查询:

  • 查找没有的公司creation
    • var ref = new Firebase(fbUrl+'/companies').orderByChild("creation").equalTo(null);
  • 找到 creation 的公司:
    • var ref = new Firebase(fbUrl+'/companies').orderByChild("creation").startAt(!null);
  • 您可以将 ".indexOn": "creation" 添加到规则中。

编辑2:我很好奇,所以我将11,000条记录推送到/companies2(一半有creation children,一半没有).使用上述查询(或我在下面显示的变体之一),我能够在大约 4 秒内检索到 5500 条匹配记录。

编辑 3: 如果您经常 运行 这些查询,将 children 和 /companies 分开可能是值得的根据 creation 的存在分为两个垃圾箱。这样,您就可以分别读取这两个段,而不必依赖查询。

工厂

这是修改后的工厂的样子(我修改了 PLNKR 以匹配):

app.factory("CompaniesFactory",function($q, fbUrl){
  return function(hasCreation){
    var deferred = $q.defer();
    var ref = new Firebase(fbUrl+'/companies').orderByChild("creation");
    var query;
    if (hasCreation) {
      query = ref.startAt(!null);
      // or: 
      // query = ref.startAt(true);
    } else {
      query = ref.equalTo(null);
      // or:
      // query = ref.endAt(!null);
      // query = ref.endAt(true);
    }
    query.once("value", function(dataSnapshot){
      deferred.resolve(dataSnapshot.val());
    }, function (error) {
      deferred.reject(error);
    });
    return deferred.promise;
  }
});

是的,可以在 returned dataSnapshot 上调用 .on('child_added')。参见 DataSnapshot.ref()



使用额外参数的原始答案:

(留作参考)

另一种方法是将另一个名为 hasCreation 的参数添加到具有 creationcompanies 的 children 中,然后通过该参数进行查询。

数据

  • 查询将是 var ref = new Firebase(fbUrl+'/companies').orderByChild("hasCreation").equalTo(hasCreation);
    • 如果查询中的hasCreationnull,查询将return没有hasCreation的公司child。
    • 如果查询中的 hasCreationtrue,则查询将 return 包含 hasCreation===true 的公司。
{
  "company1" : {
    "creation" : {
      "name" : "company1"
    },
    "hasCreation" : true
  },
  "company2" : {
    "name" : "company2"
  },
  "company3" : {
    "name" : "company3"
  },
  "company4" : {
    "creation" : {
      "name" : "company4"
    },
    "hasCreation" : true
  }
}

规则

您可以像这样将 ".indexOn" : "hasCreation" 添加到您的规则中:

  "so:29179389":{
    ".read" : true,
    ".write" : true,
    "companies" : {
      ".indexOn" : "hasCreation"
    }
  }

公司工厂

app.factory("CompaniesFactory",function($q, fbUrl){
  return function(hasCreation){
    var deferred = $q.defer();
    if (!hasCreation) {
      hasCreation = null;
    }
    var ref = new Firebase(fbUrl+'/companies').orderByChild("hasCreation").equalTo(hasCreation);
    ref.once("value", function(dataSnapshot){
      deferred.resolve(dataSnapshot.val());
    });
    return deferred.promise;
  }
});

控制器

app.controller('HomeController',function($scope,fbUrl,CompaniesFactory) {
 $scope.getCompanies = function(hasCreation) {
  var companies = new CompaniesFactory(hasCreation).then(function(data){
     console.log(data);
     $scope.companies = data;
   });
 }
});

HTML

<body ng-app="sampleApp">
  <div ng-controller="HomeController">
    <button ng-click="getCompanies(true)">Find with creation</button>
    <button ng-click="getCompanies(false)">Find without creation</button>
    <h2>Companies:</h2>
    {{companies}}
  </div>
</body>