I am trying to get a form upload working to upload data to my Firestore db as well as upload an image to my firebase storage.
Individually I can do both, however outside of storing the exact URL of the uploaded image I can't seem to figure out how to programatically store the Reference to the image in my firestore.
In the console I can set the type to "Reference"
But whatever I try programatically doesn't work:
Post image upload:
const url = await storageRef.snapshot.ref.getDownloadURL()
let imageRef = storage.ref().child(`test/${this.imageData.filename}`).ref
// let imageRef = storageRef.snapshot.ref
// let imageRef = storage.ref(`test/${this.imageData.name}`)
const docRef = await testImagesCollection.add({
thumbnail: imageRef,
dateCreated: firestore.FieldValue.serverTimestamp()
})
alert("upload succeeded", docRef.id)
I usually end up with: FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: a custom Reference object (found in field thumbnail)
If I have to I'll just store the URL but I rather not do that, if the console allows me to set a reference I should be able to do it programatically as well?!
Firestore reference types only work with references to other documents represented as DocumentReference objects. They don't work with references to objects in Cloud Storage. If you want to store a reference to an object in Cloud Storage, you should either store the path to the file in the bucket (as a string, not as a Reference object), or a download URL (whichever is more convenient for you).
If you have a Reference object, you can get a string path to it with its fullPath property.
Related
I have a bulk amount of data in CSV format. I am able to upload that data with python by converting them to the dictionary (dict) with loop. the whole data is getting uploaded.
but now I want to upload bulk data to firebase and images to storage and I want to link between each document and image because i am working on e-commerce react app. so that I can retrieve documents along with images.
which is a good way to do this? should I do this with javascript or python?
I uploaded data manually to firebase by importing from there but again I am unable to upload bulk images to storage and also unable to create references between them. please give me a source where I can find this solution
This is tough, because it's hard to fully understand how exactly your images and CSV's are linked, but generally if you need to link something to items stored in Firebase, you can get a link either manually (go into storage, click and item, and the 'Name' Field on the right hand side is a link), or you can get it when you upload it. So for example, I have my images stored in firebase, and a postgres database with a table storing the locations. In my API (Express), when I post the image to blob storage, I create the URL of the item, and post that as an entry in my table, as well as setting it to be the blobs name. I'll put the code here, but obviously it's a completely different architecture to your problem, so i'll try and highlight the important bits (it's also JS, not Python, sorry!):
const uploadFile = async () => {
var filename = "" + v4.v4() + ".png"; //uses the uuid library to create a unique value
const options = {
destination: filename,
resumable: true,
validation: "crc32c",
metadata: {
metadata: {
firebaseStorageDownloadTokens: v4.v4(),
},
},
};
storage
.bucket(bucketName)
.upload(localFilename, options, function (err, file) {});
pg.connect(connectionString, function (err, client, done) {
client.query(
`INSERT INTO table (image_location) VALUES ('${filename}')`, //inserts the filename we set earlier into the postgres table
function (err, result) {
done();
if (err) return console.error(err);
console.log(result.rows.length);
}
);
});
console.log(`${filename} uploaded to ${bucketName}.`);
};
Once you have a reference between the two like this, you can just get the one in the table first, then use that to pull in the other one using the location you have stored.
Following is the code for pushing images to fire storage.
item.images.forEach((image) => {
this.pushImage(image, `items/${this.itemId}/images/`);
});
And
pushImage(image, basePath) {
const imgId = returnRandStr();
const route = `${basePath}${imgId}`;
const imageRef = this.angularFireStorage.ref(route);
return concat(
imageRef.put(image)
.snapshotChanges().pipe(ignoreElements()),
defer(() => imageRef.getDownloadURL())
).toPromise()
}
The image object has the following form
File {
lastModified: 1604278838065
lastModifiedDate: xxx
name: "image_test.jpeg"
size: 131560
type: "image/jpeg"
webkitRelativePath: ""
}
So the images is an array.
But the issue is that I'm getting the following error:
vendor.js:16168 ERROR FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: a custom File object
enter image description here
NOTE note that if I push the image to storage without storing it inside an array (ie. as soon as I receive the $event.target.files[0] directly), then I won't receive this error message. But when I store the image inside an array and loop through the array and perform push function for each image then this error is throw. (seems like storing the image file is causing the issue, but I've double checked it before the pushing, it is still the same File {} object.)
NOTE THAT EVEN THOUGH THIS ERROR IS THROWN THE IMAGE IS GETTIN UPLOADED TO FIRESTORAGE. && Also I'm receiving back the resolved image download url.
so how can I prevent this exception. I've checked the image object before it is pushed to fire storage (it is still the same File {} object). Not sure what is happening when I store it inside an array!!
It says: "Unsupported field value: a custom File object". Firebase doesn't support class instance object when you set, add a document.
To remove this error, convert your file object to a pure js object by doing so:
const file = new file();
docRef.set(Object.assign({}, file));
In your code, I think the error triggers when you call the put method, because your image is a File object:
...
return concat(
imageRef.put(Object.assign({}, image))
.snapshotChanges().pipe(ignoreElements()),
defer(() => imageRef.getDownloadURL())
).toPromise()
...
Or try to find a docRef.set() or docRef.add() call in your code with a class instance object as a param.
When uploading an image in Storage, I want to be able to get the fullPath or an imageURL and save it under my 'Articles' documents in Cloud Firestore. So basically, I have a form with a 'title' and the upload image should be a part of it. However, I don't know how to make each image know to which article it belongs to. This is what I have so far but I'm not sure it's fine. I only manage to save the images in Storage, nothing else.
What do I do so that the image knows to which article it belongs to?
function UploadFile(props) {
const { documentId } = props;
const [fileUrl, setFileUrl] = React.useState(null);
const onFileChange = async (e) => {
const file = e.target.files[0];
const storageRef = firebase.storage().ref();
const fileRef = storageRef.child(file.name);
await fileRef.put(file);
if (documentId) {
setFileUrl(
await fileRef.getDownloadURL().then((fileUrl) => {
firebase
.firestore()
.collection("articles")
.doc(documentId)
.update({
fileUrl: fileUrl,
})
.then(() => {
setFileUrl("");
});
})
);
}
};
There are two primary strategies for associating an object in Cloud Storage to some other record in a database.
Use object metadata to store a locator to the database record. Object metadata is essentially a set of key/value pairs of strings attached to the object. You could store the path to the related Firestore document in metadata, and use that to find the document easily.
Name the object in storage the same as it's named in Firestore. Firestore documents often have random IDs. You can use the same random ID in the name of the object path. All you have to do is parse the path of that object to find the document ID, and use that to build the path to the related document. The way you create the path to the document in Firestore and the path to the object in Storage don't have to be exactly the same, but it should be clear how to convert one to the other.
I have to upload an image to the firebase storage. I'm not using the web version of storage (I shouldn't use it). I am using the firebase admin.
No problem, I upload the file without difficulty and I get the result in the variable "file".
and if I access the firebase storage console, the image is there. all right.
return admin.storage().bucket().upload(filePath, {destination: 'demo/images/restaurantCover.jpg',
metadata:{contentType: 'image/jpeg'}
public: true
}).then(file =>{
console.log(`file --> ${JSON.stringify(file, null, 2)}`);
let url = file["0"].metadata.mediaLink; // image url
return resolve(res.status(200).send({data:file})); // huge data
}) ;
Now, I have some questions.
Why so much information and so many objects as a response to the upload () method? Reviewing the immense object, I found a property called mediaLink inside metadata and it is the download url of the image. but...
Why is the url different from the one shown by firebase? Why can not I find the downloadURL property?
How can get the url of firebase?
firebase: https://firebasestorage.googleapis.com/v0/b/myfirebaseapp.appspot.com/o/demo%2Fimages%2Fthumb_restaurant.jpg?alt=media&token=bee96b71-2094-4492-96aa-87469363dd2e
mediaLink: https://www.googleapis.com/download/storage/v1/b/myfirebaseapp.appspot.com/o/demo%2Fimages%2Frestaurant.jpg?generation=1530193601730593&alt=media
If I use the mediaLink url is there any problem with different urls? (read, update from ios and Web Client)
Looking at Google Cloud Storage: Node.js Client documentation, they have a link to sample code which shows exactly how to do this. Also, see the File class documentation example (below)
// Imports the Google Cloud client library
const Storage = require('#google-cloud/storage');
// Creates a client
const storage = new Storage();
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// const bucketName = 'Name of a bucket, e.g. my-bucket';
// const filename = 'File to access, e.g. file.txt';
// Gets the metadata for the file
storage
.bucket(bucketName)
.file(filename)
.getMetadata()
.then(results => {
const metadata = results[0];
console.log(`File: ${metadata.name}`);
console.log(`Bucket: ${metadata.bucket}`);
console.log(`Storage class: ${metadata.storageClass}`);
console.log(`Self link: ${metadata.selfLink}`);
console.log(`ID: ${metadata.id}`);
console.log(`Size: ${metadata.size}`);
console.log(`Updated: ${metadata.updated}`);
console.log(`Generation: ${metadata.generation}`);
console.log(`Metageneration: ${metadata.metageneration}`);
console.log(`Etag: ${metadata.etag}`);
console.log(`Owner: ${metadata.owner}`);
console.log(`Component count: ${metadata.component_count}`);
console.log(`Crc32c: ${metadata.crc32c}`);
console.log(`md5Hash: ${metadata.md5Hash}`);
console.log(`Cache-control: ${metadata.cacheControl}`);
console.log(`Content-type: ${metadata.contentType}`);
console.log(`Content-disposition: ${metadata.contentDisposition}`);
console.log(`Content-encoding: ${metadata.contentEncoding}`);
console.log(`Content-language: ${metadata.contentLanguage}`);
console.log(`Metadata: ${metadata.metadata}`);
console.log(`Media link: ${metadata.mediaLink}`);
})
.catch(err => {
console.error('ERROR:', err);
});
I'm currently creating a file upload and display feature for a web app.
I need to add a custom property (e.g accountID) so that I can later display only the images belonging to a specific account.
I'm using cfs:standard-packages with gridfs to upload/store my images.
I believe I need to add a beforeWrite function to the FS.Store but am unsure how to go about it.
The easiest way to do this is to immediately update the inserted object as follows:
var fileId = MyFiles.insert(file);
MyFiles.update({ _id: fileId },{ $set: { accountId: myAccountId }});
Note that the actual upload of the file object to the store will be asynchronous but you'll get the _id back synchronously and immediately.