【问题标题】:Firebase: How do I retrieve records from my data for which a specific key exists?Firebase:如何从存在特定键的数据中检索记录?
【发布时间】:2015-05-24 14:54:52
【问题描述】:

我在 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'),以便以后只能处理那些特定的记录。有可能吗?

【问题讨论】:

    标签: javascript angularjs firebase angularfire


    【解决方案1】:

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

    查询

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

    • 找到没有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 孩子,一半没有)。使用上述查询(或我在下面显示的变体之一),我能够在约 4 秒内检索到 5500 条匹配记录。

    编辑 3: 如果您经常运行这些查询,则可能值得根据 creation 的存在将 /companies 的子级分成两个箱。这样一来,您就可以分别读取这两个段,而无需依赖查询。

    工厂

    这是修改后的工厂的样子(我已经修改了 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;
      }
    });
    

    是的,可以在返回的数据快照上调用.on('child_added')。见DataSnapshot.ref()



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

    (留作参考)

    另一种方法是向具有creationcompanies 的子代添加另一个名为hasCreation 的参数,并通过该参数进行查询。

    数据

    • 查询将是var ref = new Firebase(fbUrl+'/companies').orderByChild("hasCreation").equalTo(hasCreation);
      • 如果查询中的hasCreationnull,则查询将返回没有hasCreation 子级的公司。
      • 如果查询中的hasCreationtrue,则查询将返回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>
    

    【讨论】:

    • @kato/@frank,如果你看到这个,我上次编辑的任何变体是否是最佳实践? !null 并没有什么意义,但它的工作原理与true 相同。 .endAt 会比 .equalTo 更有优势吗?
    【解决方案2】:

    我会设置一个条件来验证您的 xxx.firebaseio.com/Application/companies/______/creation 是否存在。在空白处,您可以设置 for 循环以刺激公司数组。然后,您可以使用 angular.forEach 创建两个数组:一个包括那些确实具有“创造”的公司,另一个包含元素的数组不包括“创作”。

    希望有帮助:)

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

    【讨论】:

    • 我也面临这种方法的问题是,我的公司数组非常大。迭代数以万计的记录来获取让我们说只有五个包含creation 键的记录会使我的应用程序停止。
    • 我在问题中添加了数据集大的信息。
    猜你喜欢
    • 2023-04-05
    • 1970-01-01
    • 2018-12-09
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2016-12-03
    • 2018-02-25
    相关资源
    最近更新 更多