英文:
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 "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;
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)文档中的第三个代码片段:
> 在某些情况下,创建一个带有自动生成的 ID 的文档引用,然后稍后使用引用是有用的。对于这种用例,您可以调用 `doc()`:
> ```javascript
> import { collection, doc, setDoc } from "firebase/firestore";
>
> // 添加带有生成的 ID 的新文档
> const newCityRef = doc(collection(db, "cities"));
>
> // 稍后...
> await setDoc(newCityRef, data);
>```
应用于您的用例,可能会类似于这样:
```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) => {
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:
- Remember the document ID for the document you want to update.
- 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():
>
> import { collection, doc, setDoc } from "firebase/firestore";
>
> // Add a new document with a generated id
> const newCityRef = doc(collection(db, "cities"));
>
> // later...
> await setDoc(newCityRef, data);
>
Applied to your use-case, that could look something like this:
const docRef = collection(db, "products");
const newDocRef = doc(docRef); // 👈 generate reference to a single new doc
{
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, { // 👈 Call setDoc, since the doc may not exist yet
imgUrl: arrayUnion(downloadURL),
}, { merge: true }); // 👈 tell it to merge values into any existing doc
}
);
}
);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论