无法在React Js中将Firebase存储下载URL添加到同一Firestore文档中。

huangapple go评论81阅读模式
英文:

Couldn't add firebase storage download url in same firestore document in React Js

问题

以下是您要翻译的代码部分:

I'm trying to upload multiple images to firebase storage and store those urls in one firestore document as an array of strings, but I couldn't add all urls in the same firestore document. Instead, it's creating different documents for each firebase storage Url.

ImageUpload.js

import React, { useState } from "react";
import { toast } from "react-toastify";
import { db, storage } from "../firebase.config";
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
import { collection, addDoc, arrayUnion, FieldValue, updateDoc } from "firebase/firestore";
import { useNavigate } from "react-router-dom";
import "./style.css";

function ImageUpload() {
  const [allImages, setAllImages] = useState([]);

  function handleAllImage(e) {
    e.preventDefault();
    setAllImages(e.target.files);
    console.log(e.target.files);
  }

  function MutipleUpload(e) {
    e.preventDefault();

    try {
      const docRef = collection(db, "products");

      for (let i = 0; i < allImages.length; i++) {
        const storageRef = ref(storage, `productImages/${allImages[i].name}`);
        const uploadTask = uploadBytesResumable(storageRef, allImages[i], {
          contentType: allImages[i].type,
        });

        uploadTask.on(
          "state_changed",
          (snapshot) => {
            const progress =
              (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
            console.log(progress);
          },
          (error) => toast.error(error.message),
          () => {
            getDownloadURL(uploadTask.snapshot.ref).then(
              async (downloadURL) => {
                await addDoc(docRef, {
                  imgUrl: arrayUnion(downloadURL),
                });
              }
            );
          }
        );
      }

      toast.success("product added successfully!");
    } catch (error) {
      console.log(error.message);
    }
  }

  return (
    <>
      <input
        type="file"
        multiple="multiple"
        onChange={handleAllImage}
        required
      />
      <button onClick={MutipleUpload} type="submit" className="buy__btn mt-3">
        Add Image
      </button>
    </>
  );
}

export default ImageUpload;

请注意,代码中的 HTML 标签和 JavaScript 部分已经分开以便更好地理解。如果有任何问题,请告诉我。

英文:

I'm trying to upload multiple images to firebase storage and store those urls in one firestore document as an array of strings, but I couldn't add all urls in same firestore document. Instead it's creating different documents for each firebase storage Url.

ImageUpload.js

import React, { useState } from &quot;react&quot;;
import { toast } from &quot;react-toastify&quot;;
import { db, storage } from &quot;../firebase.config&quot;;
import { ref, uploadBytesResumable, getDownloadURL } from &quot;firebase/storage&quot;;
import {collection ,addDoc ,arrayUnion ,FieldValue ,updateDoc} from &quot;firebase/firestore&quot;;
import { useNavigate } from &quot;react-router-dom&quot;;
import &quot;./style.css&quot;;
function ImageUpload() {
const [allImages, setAllImages] = useState([]);
function handleAllImage(e) {
e.preventDefault();
setAllImages(e.target.files);
console.log(e.target.files);
}
function MutipleUpload(e) {
e.preventDefault();
try {
const docRef = collection(db, &quot;products&quot;);
{
for (let i = 0; i &lt; allImages.length; i++) {
const storageRef = ref(storage, `productImages/${allImages[i].name}`);
const uploadTask = uploadBytesResumable(storageRef, allImages[i], {
contentType: allImages[i].type,
});
uploadTask.on(
&quot;state_changed&quot;,
(snapshot) =&gt; {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(progress);
},
(error) =&gt; toast.error(error.message),
() =&gt; {
getDownloadURL(uploadTask.snapshot.ref).then(
async (downloadURL) =&gt; {
await addDoc(docRef, {
imgUrl: arrayUnion(downloadURL),
});
}
);
}
);
}
}
toast.success(&quot;product added successfully!&quot;);
} catch (error) {
console.log(error.message);
}
}
return (
&lt;&gt;
&lt;input
type=&quot;file&quot;
multiple=&quot;multiple&quot;
onChange={handleAllImage}
required
/&gt;
&lt;button onClick={MutipleUpload} type=&quot;submit&quot; className=&quot;buy__btn mt-3&quot;&gt;
Add Image
&lt;/button&gt;
&lt;/&gt;
);
}
export default ImageUpload;

Extra text cause error "It looks like your post is mostly code; please add some more details."

答案1

得分: 0

以下是您要的代码部分的翻译:

问题出在这段代码中
每次调用 `addDoc` Firestore 都会在集合中创建一个新文档

如果您想要[更新现有文档](https://firebase.google.com/docs/firestore/manage-data/add-data#update-data),您需要执行以下步骤:

1. 记住要更新的文档的 ID
2. 然后对该文档调用 `updateDoc`

要生成文档 ID 一次然后随时进行更新请查看[添加文档](https://firebase.google.com/docs/firestore/manage-data/add-data#add_a_document)文档中的第三个代码片段:

&gt; 在某些情况下创建一个带有自动生成的 ID 的文档引用然后稍后使用引用是有用的对于这种用例您可以调用 `doc()`
&gt; ```javascript
&gt; import { collection, doc, setDoc } from "firebase/firestore"; 
&gt; 
&gt; // 添加带有生成的 ID 的新文档
&gt; const newCityRef = doc(collection(db, "cities"));
&gt; 
&gt; // 稍后...
&gt; await setDoc(newCityRef, data);
&gt;```

应用于您的用例可能会类似于这样

```javascript
const docRef = collection(db, "products");
const newDocRef = doc(docRef); // 生成一个新文档的引用

for (let i = 0; i < allImages.length; i++) {
  const storageRef = ref(storage, `productImages/${allImages[i].name}`);
  const uploadTask = uploadBytesResumable(storageRef, allImages[i], {
    contentType: allImages[i].type,
  });

  uploadTask.on(
    "state_changed",
    (snapshot) => {
      const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
      console.log(progress);
    },
    (error) => toast.error(error.message),
    () => {
      getDownloadURL(uploadTask.snapshot.ref).then(
        async (downloadURL) => {
          await setDoc(newDocRef, {
            imgUrl: arrayUnion(downloadURL),
          }, { merge: true }); // 告诉它将值合并到任何现有文档中
        }
      );
    }
  );
}

希望这有所帮助!

英文:

The problem is in this code:

getDownloadURL(uploadTask.snapshot.ref).then(
async (downloadURL) =&gt; {
await addDoc(docRef, {
imgUrl: arrayUnion(downloadURL),
});
}
);

Every time you call addDoc, Firestore create a new document in the collection.

If you instead want update an existing document, you have to:

  1. Remember the document ID for the document you want to update.
  2. Then call updateDoc on that document

To generate a document ID once and then update that all the time, have a look at the third code snippet in the documentation on adding a document:
> In some cases, it can be useful to create a document reference with an auto-generated ID, then use the reference later. For this use case, you can call doc():
>
&gt; import { collection, doc, setDoc } from &quot;firebase/firestore&quot;;
&gt;
&gt; // Add a new document with a generated id
&gt; const newCityRef = doc(collection(db, &quot;cities&quot;));
&gt;
&gt; // later...
&gt; await setDoc(newCityRef, data);
&gt;

Applied to your use-case, that could look something like this:

const docRef = collection(db, &quot;products&quot;);
const newDocRef = doc(docRef); // &#128072; generate reference to a single new doc
{
for (let i = 0; i &lt; allImages.length; i++) {
const storageRef = ref(storage, `productImages/${allImages[i].name}`);
const uploadTask = uploadBytesResumable(storageRef, allImages[i], {
contentType: allImages[i].type,
});
uploadTask.on(
&quot;state_changed&quot;,
(snapshot) =&gt; {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(progress);
},
(error) =&gt; toast.error(error.message),
() =&gt; {
getDownloadURL(uploadTask.snapshot.ref).then(
async (downloadURL) =&gt; {
await setDoc(newDocRef, { // &#128072; Call setDoc, since the doc may not exist yet
imgUrl: arrayUnion(downloadURL),
}, { merge: true }); // &#128072; tell it to merge values into any existing doc
}
);
}
);
}
}

huangapple
  • 本文由 发表于 2023年2月19日 02:58:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/75495688.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定