从ID数组中获取一组Firestore文档。

4
我有一个Firestore集合,其中一个值是一个包含文档ID的数组。 我需要检索集合中的所有项,以及存储在数组ID中的所有文档。 这是我的集合结构 enter image description here 我的代码:
export const getFeaturedMixes = functions.https.onRequest((request, response) => {
    let result:any[] = []
    featuredMixes.get().then(mixesSnap => {

        mixesSnap.forEach(doc => {
            let docId = doc.id
            let ids = doc.data().tracks

            let resultTracks:any[] = []
            ids.forEach(id => {
                let t = tracksCollection.doc(id.track_id).get()
                resultTracks.push({'id' : id.track_id, 'data': t})
            })
            result.push({'id':docId, 'tracks': resultTracks})
        })
        return result
    })
    .then(results => {
        response.status(200).send(results)
    }).catch(function(error) {
        response.status(400).send(error)
    })
});

我得到了这个回应:
{
        "id": "Xm4TJAnKcXJAuaZr",
        "tracks": [
            {
                "id": "FG3xXfldeJBbl8PY6",
                "data": {
                    "domain": {
                        "domain": null,
                        "_events": {},
                        "_eventsCount": 1,
                        "members": []
                    }
                }
            },
            {
                "id": "ONRfLIh89amSdcLt",
                "data": {
                    "domain": {
                        "domain": null,
                        "_events": {},
                        "_eventsCount": 1,
                        "members": []
                    }
                }
            }
    ]
}

响应不包含文档数据

2个回答

2

get() 方法是异步的并返回一个 Promise。因此,您不能这样做:

 ids.forEach(id => {
      let t = tracksCollection.doc(id.track_id).get()
      resultTracks.push({'id' : id.track_id, 'data': t})
 })

您需要等待由get()方法返回的Promise解决,以便能够使用t(它是一个DocumentSnapshot)。
为此,因为您想要并行获取多个文档,所以需要使用Promise.all()
下面的代码应该可以解决问题。请注意,它尚未经过测试,并且仍有一部分容易完成的代码需要您完成,请参见末尾的注释。如果在完成它时遇到问题,请将您的新代码添加到您的问题中。
export const getFeaturedMixes = functions.https.onRequest((request, response) => {
    let result: any[] = []

    const docIds = [];

    featuredMixes.get()
        .then(mixesSnap => {


            mixesSnap.forEach(doc => {
                let docId = doc.id
                let ids = doc.data().tracks

                const promises = []

                ids.forEach(id => {
                    docIds.push(docId);
                    promises.push(tracksCollection.doc(id.track_id).get())
                })

            })

            return Promise.all(promises)
        })
        .then(documentSnapshotArray => {

            // Here documentSnapshotArray is an array of DocumentSnapshot corresponding to
            // the data of all the documents with track_ids

            // In addition, docIds is an array of all the ids of the FeaturedMixes document

            // IMPORTANT: These two arrays have the same length and are ordered the same way

            //I let you write the code to generate the object you want to send back to the client: loop over those two arrays in parallel and build your object


            let resultTracks: any[] = []

            documentSnapshotArray.forEach((doc, idx) => {
                // .....
                // Use the idx index to read the two Arrays in parallel

            })

            response.status(200).send(results)

        })
        .catch(function (error) {
            response.status(400).send(error)
        })
});

这个解决方案的性能如何?使用一个包含完整文档ID列表的条件where是否不是更好的解决方案?in运算符有什么限制吗?在查询中不能使用文档ID吗? - angelcervera
@angelcervera 对于这个特定的用例(和数据模型),唯一可能的方法是并行发出一组“单文档查询”。在你获取文档 ID 列表并想要获取它们的情况下,不能使用带有或不带有 in 操作符的 where 子句。 - Renaud Tarnec

0

谢谢Renaud Tarnec!你的回答真的很有帮助,函数已经可以工作了。不过我更想返回一个Promise.all(primises)对象,其中包含混音和它的轨道,因为现在在then函数中构建新对象比较困难。

这是我的最终函数。
    const mixIDs: any[] = [];
    const mixes:any[] =[]

    featuredMixes.get()
        .then(mixesSnap => {
            const promises:any[] = []

            mixesSnap.forEach(doc => {
                let mixId = doc.id
                let mix = createMix(doc)
                mixes.push(mix)

                doc.data().tracks.forEach(track => {
                    let promise = tracksCollection.doc(track.track_id).get()
                    promises.push(promise)
                    mixIDs.push(mixId)
                })
            })
            return Promise.all(promises)
        })
        .then(tracksSnapshot => {

            let buildedTracks = tracksSnapshot.map((doc, idx) => {
                let mId = mixIDs[idx]
                return createTrack(doc, mId)
            })

            let result = mixes.map(mix => {
                let filterTracks = buildedTracks.filter(x => x.mix_id === mix.doc_id)
                return Object.assign(mix, {'tracks': filterTracks})
            })
            response.status(200).send(result)
        })
        .catch(function (error) {
            response.status(400).send(error)
        })
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接