[solved] CollectionFS - Connect files to documents from other collections


#1

Situation

I have two collections:

  1. Products (basic Mongo.Collection)
  2. Images (basic FS.Collection)

Inserting documents to the Products Collection works.
Uploading images to the Images Collection works.

Problem

Images are always connected to a Product.
So I need to add this information to an image-document on insert.

My idea was to simply add the id of the corresponding document from the Products Collection.
That should be enough. Pretty simple, right?

So a document from the Images Collection should look like this:

    {
        "_id": "Go6irzAtxS7vcPz4Z",
   -->  "product": [Product Id here],
   -->  "otherInfo": [Some other info here]
        "original": {
        "name": "pictures_1323548695384.jpg",
        "updatedAt": "2011-12-13T23:40:37.909Z",
        "size": 54894,
        "type": "image/jpeg"
    },
        "uploadedAt": "2015-07-03T17:24:58.838Z",
        "copies": {
             "images": {
                  "name": "pictures_1323548695384.jpg",
                  "type": "image/jpeg",
                  "size": 54894,
                  "key": "5596c56a19d5a8fda6b62e72",
                  "updatedAt": "2015-07-03T17:24:58.927Z",
                  "createdAt": "2015-07-03T17:24:58.927Z"
             }
         }
     }

I dont understand how I to add these additional key:value pairs (here: “product” & “otherInfo”) to a FS.Collection document on insert.

My current insert looks like this:
(Pretty much straight from the docs)

Template.form_products_add.events({
	'change .fileinput': function(event, template) {
		FS.Utility.eachFile(event, function(file) {
			Images.insert(file, function (err, fileObj) {
				
	    		});
		});
	}
});

Thanks for any push in the right direction. .-)

Cheers!


#2

Can’t you just do something like:

Template.form_products_add.events({
	'change .fileinput': function(event, template) {
		FS.Utility.eachFile(event, function(file) {
// only changed the next line
			Images.insert(_.extend(file, {product:'myproductid', otherInfo: {}}), function (err, fileObj) {
				
	    		});
		});
	}
});

So basically just add whatever other data you want to add to the file? This is just a guess, I haven’t needed to do that with CFS yet. Or make changes to the fileObj as it comes back after the insert call, in the callback there. Images.update(fileObj._id, {$set:{product:'myproductid', otherInfo: {}}}; (Though you’d likely have to add an additional allow rule in order to be able to make that call, but I’m not sure.)
(Reference docs for _.extend which is an alias of _.assign: http://devdocs.io/lodash/index#assign)


#3

Hey Seeekr,

many thanks for the reply.

Yes, I was looking for something like your solution (_.extend). Makes much sense to me.
Unfortunately it’s not working. The image document is added without the additional “product” and “otherInfo”.

Strange. :-/


#4

@nilsdannemann this how I did it , this code might help you:

  'change .fileInput':function(evt,tmpl){
         thisProject = Projects.findOne({projectId: this._id});
            thisProject = this._id;
        FS.Utility.eachFile(event,function(file){
         var videoFile = new FS.File(file);
          videoFile.projectId = thisProject;
         Videos.insert(videoFile),function(err){
          console.log(err);
        }
      })
    },

#5
Template.form_products_add.events({
	'change .fileinput': function(event, template) {
		FS.Utility.eachFile(event, function(file) {
			var tmpdoc = file;
			tmpdoc['product'] = "whatever u want";
			tmpdoc['otherInfo'] = "dont modify directly file, because modifing function argument cause wrath of gods"
			Images.insert(tmpdoc, function (err, fileObj) {
				
	    		});
		});
	}
});

It is not best looking solution, but we are not in immutable class here :smiley:


#6

@hodaraadam,
you save my evening! :smiley:

I was starting to get frustrated about this!
Your solution works like a charm and i can understand it (which is always nice :D)

Many² thanks!

@shock
I didn’t try your solution because hodaraadam’s worked for me. But thanks for the “dont modify directly file, because modifing function argument cause wrath of gods:smiley: This made me understand the approach in the first place. Will keep it in mind.


#7

@hodaraadam hapy it worked! :smile: I also had a big issue with it when I needed it so found out the solution online somewhere and saved the code becase knew it would be useful in the future


#8

Hey @hodaraadam, (and all the others)
Unfortunately I’m encountering another Problem now:

Situation

  1. I trigger the Image-upload on the change event of the file-input.
    (triggering the upload on change is essential)
  2. With your advice I can now add addtional information to an uploaded Image.

Goal

Like described above:
I need to add the corresponding projectId to an Image, since an Image is always part of a specific project.

Problem

The file-input is part of the project-creation-form.

  • Usecase:
    Basically you click on “new project”, choose an Image (change-event -> Images.insert) and fill out the rest of the form while it uploads. Then you click “done” and the Project is created (submit-event -> Projects.insert).

The tricky part:
This approach means, when the change event of the file-input happens, the project is not yet created.
Thus the projectId doesn’t exist yet.
And thus I cant attach it to the Image.

How do i approach such a situation?

Somehow update the image with the projectId after the Project is created?
Or do it the other way around: Add the imageId to the Project?

@hodaraadam
Your solution works for me, but you’ve created the project before the upload happens, right?

Thanks for any kind of help or advice!


#9

@nilsdannemann I added the videos in my case after the project was created so I already had a “projectId”, I’m not sure how I would do what you are trying to achieve.

You could attach the imageId to the project but I believe you said you will have many images per project so that could create a problem in the future?

How about not doing the insert on file change? but doing the insert when they click on “create project button/submit” after project is created like:

when they click the submit button you do:
1)Projects.insert();
2) then the fs collection insert taking the value from the image in the fileinput tag? (at this point you should have a projectId right?)
3)take them to the specific project

that could work?


#10

This should be still modifying file, you’re not cloning file object just assigning it’s reference to tmpdoc, both tmpdoc and file points to the same memory block.


#11

@hodaraadam
I came up with a solution to the problem. :smile:
For the sake of completion I’m posting it here.

Solution

To connect images with projects I did this:

  1. When the user is routed the Project-Creation-Form I generate a “shared Id” and store it in a Session.
  2. Then I attach it to each image on insert.
  3. Finally I attach it to the project on insert.

Works like a charm so far.
The image upload happens in the background while the user fills out the rest of the form.
And when I delete a project I just delete all images that have the same “shared Id”.

Thanks for the help everyone!


#12

@nilsdannemann
I have the same problem with you however in my case I just wanted the url of the image file in my product collection. The reason for this is that when I show the the products they can click the download link of the image.
I honestly don’t know how to do it and the CollectionFS document only show the {{url}} helper.

Any help is much appreciated.