假设我有一个评论集合。每个评论对象都有一个指向发帖用户的“文档引用”。我需要查询返回一个评论列表,其中包括每个用户引用的值,以便我的查询返回格式良好的Json评论对象。
假设我有一个评论集合。每个评论对象都有一个指向发帖用户的“文档引用”。我需要查询返回一个评论列表,其中包括每个用户引用的值,以便我的查询返回格式良好的Json评论对象。
这里曾经有一个类似的问题被问到Firebase Firestore参考数据类型有什么用处?,根据这个答案https://dev59.com/-lYN5IYBdhLWcg3w-sl-#46570119,我认为你所要求的不可能实现。
你需要自己加载每个引用,例如:
const comments = []
firebase.firestore().collection('/comments').get().then(snapshot => {
snapshot.docs.forEach(doc => {
const comment = doc.data()
comment.userRef.get().then(snap => {
comment.user = snap.data()
comments.push(comment)
})
})
})
对于许多评论来说,这将增加很多开销。也许您可以编写一个云函数,在服务器端完成所有工作并返回格式化的JSON。
不过看起来他们可能正在努力支持这一点: https://dev59.com/MlYN5IYBdhLWcg3w9Mbr#46614683
这也让我非常恼火。我创建了一个实用程序帮助器,可以自动填充第一层。
帮助器(Helper)
import { get, set } from 'lodash'
const getReference = async documentReference => {
const res = await documentReference.get()
const data = res.data()
if (data && documentReference.id) {
data.uid = documentReference.id
}
return data
}
const hydrate = async (document, paths = []) => Promise.all(
paths.map(async path => {
const documentReference = get(document, path)
if (!documentReference || !documentReference.path) {
return console.warn(
`Error hydrating documentReference for path "${path}": Not found or invalid reference`
)
}
const result = await getReference(documentReference)
set(document, path, result)
})
)
export { hydrate }
使用示例:
getUser = async uid => {
return this.db
.collection('users')
.doc(uid)
.get()
.then(async documentSnapshot => {
const data = documentSnapshot.data()
await hydrate(data, ['company', 'someOtherNestedRef-2', 'someOtherNestedRef-1'])
return data
})
}
限制: 此示例对于深度嵌套的引用无效
我建议在每个评论中复制用户数据。在评论文档中创建一个名为user
的对象字段,并提供显示评论所需的最少信息。因此,您的comment
文档可能如下所示...
{
id: 'CEXwQAHpk61vC0ulSdZy',
text: 'This is a comment',
user: {
id: 'd5O4jTsLZHXmD1VJXwoE,
name: 'Charlie Martin',
avatar: 'https://...'
}
}
在ChrisRich的回答中补充一点。如果所需字段是引用数组,则可以使用以下代码:
import { get, set } from 'lodash'
const getReference = async documentReference => {
const res = await documentReference.get()
const data = res.data()
if (data && documentReference.id) {
data.uid = documentReference.id
}
return data
}
export default async (document, paths = []) => Promise.all(
paths.map(async path => {
const documentField = get(document, path)
if (documentField.constructor.name === 'Array') {
for (let i = 0; i < documentField.length; i++) {
const documentReference = documentField[i];
if (!documentReference || !documentReference.path) {
return console.warn(
`Error hydrating documentReference for path "${path}": Not found or invalid reference`
)
}
const result = await getReference(documentReference)
documentField[i] = result;
}
}
else {
const documentReference = documentField;
if (!documentReference || !documentReference.path) {
return console.warn(
`Error hydrating documentReference for path "${path}": Not found or invalid reference`
)
}
const result = await getReference(documentReference)
set(document, path, result)
}
})
)
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("Stock").whereEqualTo("user", userName).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isComplete()) {
Log.d(TAG, "onComplete stock : "+ task.getResult().getDocuments().toString());
List<DocumentSnapshot> list = task.getResult().getDocuments();
if (list != null && list.size()>0) {
for (DocumentSnapshot doc: list) {
StockData stockData = new StockData();
stockData.setCatergory(doc.get("catergory").toString());
stockData.setDate(doc.get("date").toString());
stockData.setUser(doc.getString("date_time"));
stockData.setUser(doc.getString("user"));
stockData.setSale_price(doc.getDouble("sale_price"));
}
}
}
}
});
我为此创建了一个解决方案,至少对我有效!
想象一下你有两个集合:用户和朋友,其中用户有一个文档:User1,朋友也有一个文档:Friend1。
因此,User1具有带有此文本的引用字段:Friends/Friend1。
您可以获取所有用户,并为每个用户构建如下的映射:
[
{
"User1":"Friend1"
}
{
"Another User":"Another Friend"
}
]