将实时数据库内容复制到Firestore时调用set函数出现SetOptions参数错误
Hey there, let's break down what's going wrong here and fix it step by step.
First, that error Error: Argument "options" is not a valid SetOptions. Input is not an object. is happening because Firestore's set() method doesn't accept a callback function as the second parameter—you're used to the Realtime Database's callback pattern, but the Firestore Admin SDK uses Promises for async operations instead.
On top of that, your code has a hidden issue: the set() calls inside the forEach are asynchronous, so checking if i equals the number of children to send the response will fire early, before all writes are actually completed.
Fixed Code
Here's the revised version with all issues addressed:
exports.copyPosts = functions.https.onRequest(async (req, res) => { try { // Fetch data from Realtime Database using async/await const postSnap = await db.ref("feeds").child("all").limitToLast(2000).once("value"); console.log(`Found ${postSnap.numChildren()} posts`); // Collect all Firestore write promises to run them in parallel const writePromises = []; let index = 0; postSnap.forEach(topic => { index++; console.log(`Processing topic: ${topic.key}`); // Map Realtime Database data to Firestore format const postData = { caption: topic.child("caption").val(), time: topic.child("time").val(), username: topic.child("username").val(), category: topic.child("category").val(), pic: topic.child("pic").val() }; // Add the set operation promise to our list const writePromise = firestore .collection("topics") .doc("all") .collection(index.toString()) .set(postData); writePromises.push(writePromise); }); // Wait for ALL write operations to finish before sending a response await Promise.all(writePromises); res.contentType('application/json'); res.status(200).send("Success"); } catch (error) { console.error("Failed to copy posts:", error); res.status(500).send(`Copy failed: ${error.message}`); } });
Key Fixes Explained
- Replaced callbacks with Promises/async-await: Firestore's
set()returns a Promise, so we useawaitto handle async operations instead of passing callbacks. This aligns with modern JS async patterns and avoids the invalid parameter error. - Used
Promise.all()for batch operations: This ensures we wait until every single post is written to Firestore before sending the success response. No more premature responses! - Added proper error handling: The
try/catchblock catches any errors from fetching data or writing to Firestore, and sends a meaningful error response instead of silently failing.
Quick Suggestion
Instead of using an incrementing index for your subcollection document IDs, consider using topic.key (the ID from the Realtime Database). This creates a direct mapping between your old and new data, making future maintenance or incremental syncs much easier. Just change collection(index.toString()) to collection(topic.key).
内容的提问来源于stack exchange,提问作者Bucky

