veliovgroup / Meteor-Files

🚀 Upload files via DDP or HTTP to ☄️ Meteor server FS, AWS, GridFS, DropBox or Google Drive. Fast, secure and robust.
https://packosphere.com/ostrio/files
BSD 3-Clause "New" or "Revised" License
1.11k stars 167 forks source link

How do you actually get the contents of a file? #804

Closed ajaypillay closed 3 years ago

ajaypillay commented 3 years ago

Hi, I'm trying to integrate this into my Meteor/React app, but I'm not quite sure on how to actually get the contents of a file. I used the same example as presented in the Readme, except I defined an absolute storagePath.

import { Meteor }          from 'meteor/meteor';
import { FilesCollection } from 'meteor/ostrio:files';

const Images = new FilesCollection({
  debug: true,
  collectionName: 'Images',
  storagePath: "/home/XXX/XXX/testDir"
});

// To have sample image in DB we will upload it on server startup:
if (Meteor.isServer) {
  Images.denyClient();
  Images.collection.attachSchema(Images.schema);

  Meteor.startup(function () {
    if (!Images.find().count()) {
      Images.load('https://raw.githubusercontent.com/VeliovGroup/Meteor-Files/master/logo.png', {
        fileName: 'logo.png',
        meta: {}
      });
    }
  });

  Meteor.publish('files.images.all', function () {
    return Images.find().cursor;
  });
} else {
  Meteor.subscribe('files.images.all');
}

export default Images;

1) On my client in React, I import Images but how am I supposed to get the actual file contents? I want to display the image but I can't use the path stored in the Images collection because Meteor parses the path through the public/ folder.

2) Similarly, if this is a text file or any other file, how do I get the contents of the file? Say if I want to get the contents of a text file and display it in a React component, how should this be done?

I couldn't find any instance in the documentation which illustrates how this should be done specifically.

I'm trying to be able to console.log the data first before actually using it in my component. I tried to use link() but I don't think this is the correct way of doing it as it throws some errors:

const Component = () => {
    useEffect(() => {
        console.log(Images.link())
    }, [])
    return <div />
}

Appreciate any help, thanks.

dr-dimitru commented 3 years ago

@ajaypillay you're looking for .link() method. Let me know if it helped you

ajaypillay commented 3 years ago

@dr-dimitru I tried the following:

const Component = () => {
    useEffect(() => {
        const fileRef = Images.collection.findOne({})
        console.log(Images.link(fileRef))
    }, [])
    return <div />
}

But I get this Uncaught errorClass:

errorType: "Match.Error"
message: "Match error: Expected object, got undefined"
path: ""
sanitizedError: errorClass
    details: undefined
    error: 400
    errorType: "Meteor.Error"
    isClientSafe: true
    message: "Match failed [400]"
    reason: "Match failed"
    stack: "Error: Match failed [400]\n    at errorClass.<anonymous> (http://XXX.XXX.XX.XX:3000/packages/check.js?hash=75a
details: undefined
error: 400
errorType: "Meteor.Error"
isClientSafe: true
message: "Match failed [400]"
reason: "Match failed"
stack: "Error: Match failed [400]\n    at errorClass.<anonymous> (http://XXX.XXX.XX.XX:3000/packages/check.js?hash=75ac
ajaypillay commented 3 years ago

Nevermind, I got it working. I was doing this in React when in actuality it needs to be done on the server side. I'm running a Meteor/Apollo/React stack and I made a simple Graphql resolver to fetch the links, and it all works now because it's being done on the server-side.

Thank you!

dr-dimitru commented 3 years ago

@ajaypillay I'm glad this issue was solved quickly. Are you using Meteor methods in your solution? There's also a way to publish/subscribe it as any other Meteor collection and those functions would work on a Client. But to be honest methods work better than pub/sub, and I prefer methods to pub/sub on "normal" meteor Collections

Please support this project with:

ajaypillay commented 3 years ago

@dr-dimitru

I'm not using any Meteor methods actually, as Apollo/Graphql gives an interface to handle all operations with the database. I defined a Graphql query schema in Files.graphql:

extend type Query {
    getFiles: String
}

And I have a separate file for the actual FileCollection, in files.jsx:

import { FilesCollection } from 'meteor/ostrio:files'
const Files = new FilesCollection({
    debug: true,
    collectionName: 'Files',
    storagePath: "/XXX/XXX/XXX/directory"
})
export default Files

And in resolvers.jsx I have:

import Files from "./files";
export default {
    Query: {
        getFiles(obj, args, context) {
            return Files.collection.findOne({}).link(fileRef, 'original, 'http://XXX.XXX.XX.XX:3000/')
        }
    }
}

And then in my React component I just query the database for the needed data.

import React from "react"
import { gql, useQuery } from '@apollo/client'

const Component = () => {
    const {data, loading, error} = useQuery(gql`
        query getFiles {
            getFiles: getFiles
        }
    `)
    if (loading) return <div />
    if (error) console.log(error)
    console.log(data) // Data will contain the URL string returned by the query
    return (
        <div />
    )
}

And then I can use data in my component. I've found working with Apollo/Graphql very convenient, and I've abstracted away all the database logic to Apollo. The only thing I'm really using Meteor for right now explicitly is for the accounts package, and other nice things like hot-reloading.

dr-dimitru commented 3 years ago

@ajaypillay good Graphql use case, thank you for sharing in details