我必须在同一引用中从不同的子级获得不同的值。在Swift中,我会这样做:
var sum = 0
var totalPosts = 0
var starRating = 0 // run some calculations on totalPosts + sum
let sneakersRef = Database.database().reference().child("sneakers").child(adidas_ABC) // postId
sneakersRef.observeSingleEvent(of: .value, with: { (snapshot) in
if !snapshot.exists() { return }
if snapshot.hasChild("postCount") {
let childSnapshot = snapshot.childSnapshot(forPath: "postCount")
if let postCount = childSnapshot.value as? Int {
self.totalPosts = postCount
}
}
}
if snapshot.hasChild("fans") {
let childSnapshot = snapshot.childSnapshot(forPath: "fans")
for child in childSnapshot.children {
let userId = child as! DataSnapshot
for snap in userId.children {
guard let dict = snap.value as? [String:Any] else { continue }
let price = dict["price"] as? Int ?? 0
self.sum += price
}
// update ref with value obtained from sum and create/update a starRating
}
}
})
在云功能中,我该如何做同样的事情下面childSnapshot.forEach((child) => { }
中的代码是我需要帮助的内容。
exports.updateValues = functions.https.onCall((data, context) => {
const postId = data.postId; // adidas_ABC
var sum = 0;
var totalPosts = 0;
var starRating = 0;
const sneakersRef = admin.database().ref('sneakers').child(postId);
sneakersRef.once('value', snapshot => {
if (snapshot.exists()) {
const postCount = snapshot.child("postCount").val();
totalPosts = postCount
const childSnapshot = snapshot.child("fans").val().userID;
// the code in this loop is questionable
childSnapshot.forEach((snap) => {
const price = snap.child("price").val();
sum += price
})
// run calculations to get starRating
return sneakersRef.update({ "sum": sum, "starRating": starRating }).then(() => {
})
.catch((error) => {
console.log('something went wrong: ', error);
});
} else {
console.log('doesn't exist');
}
});
});
这是我的数据库布局:
@sneakers
@adidas_ABC // same postId for anything dealing with adidas
@fans // this might not exist in which case postCount would be zero
@userId_XYZ
@postId_123
-condition: "used"
-price: 100
-type: shell_top
@postId_456
-condition: "new"
-price: 500
-type: yeezy
-fanCount: 1
-postCount: 2
-sum: 600
-starRating: 4
在代码中有两件事需要调整:
- 您需要在
user
对象上循环,然后需要在每个user
对象的每个post
上循环。请参阅此SO答案以了解更多详细信息 - 您需要通过返回Promises链来正确管理云功能的生命周期。正如您在文档中看到的那样,通过返回JavaScript承诺来终止执行异步处理的云函数是键。在您的情况下,我们返回Promise链,它是一个Promise,由异步Firebase方法(
once()
和update()
(和then()
返回的Promise组成。为此,我们需要使用";承诺的";once()
方法的版本(即once('value').then((snapshot) => {..})
(,而不是您在代码中使用的回调版本
所以以下应该可以做到:
exports.updateValues = functions.https.onCall((data, context) => {
const postId = data.postId; // adidas_ABC
var sum = 0;
var totalPosts = 0;
var starRating = 0;
const sneakersRef = admin.database().ref('sneakers').child(postId);
return sneakersRef // Note the return here!! => We return the Promise chain
.once('value')
.then((snapshot) => {
if (snapshot.exists()) {
const postCount = snapshot.child('postCount').val();
totalPosts = postCount;
const childSnapshot = snapshot.child('fans').val();
Object.keys(childSnapshot).forEach((user) => {
const obj = childSnapshot[user];
Object.keys(obj).forEach((e) => {
const price = obj[e].price;
sum += price;
});
});
// I let you dealing with the calculations to get starRating
return sneakersRef.update({ sum: sum, starRating: starRating });
} else {
console.log("doesn't exist");
return null; // Note the return here
}
})
.catch((error) => {
console.log('something went wrong: ', error);
return null; // Note the return here
});
});