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

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!

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)

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. :-/

@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);
        }
      })
    },
4 Likes
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:

@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.

1 Like

@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

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!

@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?

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.

@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!

@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.