0

I've a function that set one JSON to my Cloud Firestore database:

app.post('/api/add/collection/:collection_id/permission/:permission_id', (req, res) => {
(async () => {
    try {
        await db.collection(req.params.collection_id)
            .doc(req.params.permission_id)
            .set({
                [req.body.id]: {
                    name: req.body.name,
                    email: req.body.email,
                    phone_number: req.body.phone_number
                }
            }, { merge: true}
            );

        return res.status(200).send('OK');
    } catch (error) {
        console.log(error);
        return res.status(500).send('ERROR' + error);
    }
})();
});

To invoke this function, I pass JSON body to POST request:

https://.../app/api/add/collection/USER_ID/permission/PERMISSION_id

{
    "id": 45,
    "name": "Stack",
    "email": "stack@overflow.com",
    "phone_number": "+48 111 222 333"
}

Everything work fine, this request set this JSON as a map with id as a key, and values as a name, email and phone_number. But I want to pass several JSON's on one request to add several map objects to my NoSQL document, like:

[
    {
        "id": 45,
        "name": "Stack",
        "email": "stack@overflow.com",
        "phone_number": "+48 111 222 333"
    },
    {
        "id": 46,
        "name": "Stack2",
        "email": "stack2@overflow.com",
        "phone_number": "+48 222 222 333"
    },
    {
        "id": 47,
        "name": "Stack3",
        "email": "stack3@overflow.com",
        "phone_number": "+48 333 222 333"
    }
]

How to modify my firebase function to achieve this?

wapn
  • 359
  • 1
  • 7
  • 19
  • That last code block you show is not a valid JSON object. Can you show what `req.body` outputs when you send the request you want to get written to the database? – Frank van Puffelen Nov 16 '19 at 14:56
  • @FrankvanPuffelen I've edited JSONs to be valid. I want to send the JSON's array as shown above. – wapn Nov 16 '19 at 15:20

1 Answers1

2

Since you have an array of objects, you'll need to loop over that array, and then create a document for each object. And since you need to wait until all documents are created, you can use Promise.all().

Something like this:

try {
    await Promise.all(req.body.map((object) => {
        return db.collection(req.params.collection_id)
          .doc(req.params.permission_id)
          .set({
            [object.id]: {
                name: object.name,
                email: object.email,
                phone_number: object.phone_number
            }
          }, { merge: true});
    });
    return res.status(200).send('OK');
} catch (error) {
    console.log(error);
    return res.status(500).send('ERROR' + error);
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • It might make more sense to use a [batched write](https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes) rather than `Promise.all()` so that the entire set either succeed or fail together. – robsiemb Nov 16 '19 at 16:59
  • It's an option, but I didn't see any relation between these objects. In that case a batched write doesn't add anything, and is usually slower than the individual writes. – Frank van Puffelen Nov 16 '19 at 17:06
  • I guess it depends on how error handling in the (single) request that is being served is done -- if partial writes are ok, then no problem. – robsiemb Nov 16 '19 at 17:08
  • Also, [the documentation](https://cloud.google.com/firestore/docs/best-practices#read_and_write_operations) states that batched writes are more efficient overall (though its not super clear why -- could just be the per-request network/http overhead?) – robsiemb Nov 16 '19 at 21:10
  • 1
    I'll file a bug report against that document page, as the statement is not true. The difference in overhead is small, and using a batch removes the option for parallelizing the calls. The latter is more likely to have a positive performance impact than the reduction in overhead. – Frank van Puffelen Nov 16 '19 at 21:30
  • I actually just found this statement in the [Firebase docs for batched writes](https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes): "For bulk data entry, use a server client library with parallelized individual writes. Batched writes perform better than serialized writes but not better than parallel writes." In the code I gave in my answer, the writes are executed in parallel. – Frank van Puffelen Nov 16 '19 at 21:39
  • 2
    I decided to give it a spin, and write my findings up in a separate answer here: https://stackoverflow.com/q/58897274 – Frank van Puffelen Nov 17 '19 at 03:37