如何在某个时间点获取列表中的多个对象

时间:2016-05-11 02:11:39

标签: firebase

我想为我的用户提供一个API(指向我的服务器),它将从Firebase获取数据并将其返回给他们。我希望它是一个正常的'时间点请求(与流式传输相反)。

我的数据是'框'在'项目'。用户可以查询我的API以获取项目的所有框。

我的数据已标准化,因此我将查找项目并获取该项目中框的键列表,然后单独获取每个框记录。一旦我拥有它们,我将把数组返回给用户。

我的问题:最好的方法是什么?

这是我拥有的,而且有效。但它感觉太乱了。

  const projectId = req.params.projectId; // this is passed in by the user in their call to my server.

  const boxes = [];
  let totalBoxCount = 0;
  let fetchedBoxCount = 0;

  const projectBoxesRef = db
    .child('data/projects')
    .child(projectId)
    .child('boxes'); // a list of box keys

  function getBox(boxSnapshot) {
    totalBoxCount++;

    db
      .child('data/boxes') // a list of box objects
      .child(boxSnapshot.key())
      .once('value')
      .then(boxSnapshot => {
        boxes.push(boxSnapshot.val());

        fetchedBoxCount++;

        if (fetchedBoxCount === totalBoxCount) {
          res.json(boxes); // leap of faith that getBox() has been called for all boxes
        }
      });
  }

  projectBoxesRef.on('child_added', getBox);

  // 'value' fires after all initial 'child_added' things are done
  projectBoxesRef.once('value', () => {
    projectBoxesRef.off('child_added', getBox);
  });

关于分离初始child_added个对象的问题还有一些其他问题/答案,它们影响了我当前的决定,但它们似乎并没有直接相关。

感谢卡车装载任何帮助。

更新:Jay的答案的JavaScript版本如下:

db
  .child('data/boxes')
  .orderByChild(`projects/${projectId}`)
  .equalTo(true)
  .once('value', boxSnapshot => {
    const result = // some parsing of response

    res.json(result);
  });

2 个答案:

答案 0 :(得分:1)

这可能是一个简单的解决方案,但如果您有项目,并且每个项目都有框

您的项目节点

projects
  project_01
    boxes
      box_id_7: true
      box_id_9: true
      box_id_34: true
  project_37
    boxes
      box_id_7: true
      box_id_14: true
      box_id_42: true

和框节点

boxes
  box_id_7
    name: "a 3D box"
    shape: "Parallelepiped"
    belongs_to_project
       project_01: true
  box_id_14
    name: "I have unequal lenghts"
    shape: "Rhumboid"
    belongs_to_project
       project_37: true
  box_id_34
    name: "Kinda like a box but with rectangles"
    shape: "cuboid"
    belongs_to_project
       project_01: true 

这样,在box节点上只有一个(深度)查询将加载属于project_01的所有框,在本例中为box_id_7和box_id_34。

您可以采用另一种方式,因为您知道项目节点中每个项目的框ID,您可以通过它的特定路径/ box / box_id_7等执行一系列观察者来加载每个项目。我更喜欢这个问题;更快,更少的带宽。

如果一个方框可以属于多个项目,你可以对此进行扩展:

  box_id_14
    name: "I have unequal lenghts"
    shape: "Rhumboid"
    belongs_to_project
       project_01: true
       project_37: true

现在在框节点上查询属于project_01的所有框将获得box_id_7,box_id_14和box_id_34。

编辑:

一旦该结构到位,使用深度查询然后获取属于相关项目的框。

例如:假设您要制作一个Firebase Deep Query来返回框中所属的框__ project_toject列表包含一个带有键的项目" project_37"

boxesRef.queryOrderedByChild("belongs_to_project/project_37"
    .queryEqualToValue(true)
    .observeSingleEventOfType(.Value, withBlock: { snapshot in
        print(snapshot)
})

答案 1 :(得分:0)

好的,我觉得我对我的方法感到满意,一旦所有单个“查询”都被返回,使用Promise.all回复:

我改变了使用promises的方法,然后调用Promise.all()表示所有数据都已准备好发送。

const projectId = req.params.projectId;

const boxPromises = [];

const projectBoxesRef = db
  .child('data/projects')
  .child(projectId)
  .child('boxes');

function getBox(boxSnapshot) {
  boxPromises.push(db
    .child('data/boxes')
    .child(boxSnapshot.key())
    .once('value')
    .then(boxSnapshot => boxSnapshot.val())
  );
}

projectBoxesRef.on('child_added', getBox);

projectBoxesRef.once('value', () => {
  projectBoxesRef.off('child_added', getBox);

  Promise.all(boxPromises).then(boxes => res.json(boxes));
});