3

In my users profile collection I have array with image objects in it.

A user can have a max of 3 images in their profile collection. If the user has 3, throw an error that the maximum has been reached. The user has the option to remove an image themselves in the frontend.

I thought the solution would be to check the length of the array with $size. if it's less then 3, insert the image, else throw error.

I'm using the tomi:upload-jquery package.

client:

  Template.uploadImage.helpers({
    uploadUserData: function() {
        return Meteor.user();
    },
    finishUpload: function() {
        return {
            finished: function(index, fileInfo, context) {

                Meteor.call('insert.profileImage', fileInfo, function(error, userId) {
                    if (error) {
                        // todo: display modal with error
                        return console.log(error.reason);
                    } else {
                        // console.log('success ' +userId);
                        // console.log('success ' + fileInfo);
                    }
                });
            }
        };
    }
});

The method (server) I use:

'insert.profileImage': function(postImage) {
    check(postImage, Object);

    // check array profile.images max 3

    Meteor.users.update(this.userId, {
        $push: {
            'profile.images': postImage
        }
    });
},
4
  • Is a 4th image not allowed or is it supposed to replace an earlier image? Your template code is updating the profile, which places a lot of trust in the clinet. Are you doing that anywhere else in your app? I ask because a better solution here is to use methods for profile updates. Commented May 7, 2015 at 13:56
  • So the solution you are asking for does not include the replacement of an item in the images array if I understand correctly? You should edit it in the question itself, it wasn't very clear. Commented May 7, 2015 at 14:25
  • @DavidWeldon hm, yeah I'm actually updating in several places. But I'm using methods here right? Commented May 7, 2015 at 14:34
  • @Kyll made the question more clear Commented May 7, 2015 at 14:34

2 Answers 2

1

You may do it with a function using the $where operator:

'insert.profileImage': function(postImage) {
    var updateResults;
    check(postImage, Object);

    updateResults = Meteor.users.update(
    {
        _id : this.userId,
        $where : 'this.profile.images.length < 3' //'this' is the tested doc
    },
    {
        $push: {
            'profile.images': postImage
        }
    });

    if(updateResults === 0) {
       throw new Meteor.Error('too-many-profile-images', 
         'A user can only have up to 3 images on his/her profile');
    }
},

The Mongo docs warns about potential performance issues (if you run a JavaScript function on all documents of the store, you're in for bad surprises) but since we also search by _id I guess it should be fine.

This way, the update just doesn't run if the user has too many images. You can also check the number of affected document (the return value of the update) to know if something happened. If nothing (returns 0) happened, there's not many possibilities: The user has too many images.

Sign up to request clarification or add additional context in comments.

4 Comments

thx! I've been testing and messing around with the code, but updateResults always returns 1
Mh, weird, I can't see what's wrong. I'll do some testing. Gosh, no one here did a right answer on the first try it seems >.>
@flowen Found it! Actually, you can't pass a function with $where, you have to pass embedded JavaScript in a string (see this Google Groups discussion). Tested it, it works.
haha yeah, maybe my aura. This indeed works! Thanks so much. So my learning here is using $where to pass in JS expressions and check it. Wouldn't have ever assumed to use $where for that. Thanks!
0

Use the $exists operator to check the existence of all documents that have at least a fourth profile image array element (index position 3) with the dot notation. For example you could use it to check whether the size of the profile.image array is greater than 3 with the find() method as follows:

var hasSizeGreaterThanThree = Meteor.users.find( 
    {
        '_id': this.userId, 
        'profile.image.3': { '$exists': true }
    }).count() > 0;

So you could use that in your code as:

'insert.profileImage': function(postImage) {
    check(postImage, Object);

    // check array profile.images max 3
    var hasSizeGreaterThanThree = Meteor.users.find( 
        {
            '_id': this.userId, 
            'profile.image.3': { '$exists': true }
        }).count() > 0;

    if (!hasSizeGreaterThanThree){
        Meteor.users.update(this.userId, {
            $push: {
                'profile.images': postImage
            }
        });
    }
},

6 Comments

thanks for the reply! I'm getting an error though: $err" : "Can't canonicalize query: BadValue $size needs a number", "code" : 17287
@flowen My apologies for giving you the wrong code, it was untested. Please review my updated answer, thanks.
count() > 0 is a condition which checks to see whether the number of documents returned by the find() cursor with the 'profile.image.3': { '$exists': true } query is greater than 0, if that's true then that means there are documents which have the more than three profile images in the array. Hope that helps to understand why we need the condition. You could also do .count() === 0 to check if the document has less than 4 elements.
ok this new change seems to not work as hasSizeGreaterThanThree always returns false.
That means the user has got the profile images array size less than 4, isn't that what you are expecting? Can you do a simple query for a specific user that you know has the array size greater than 3 in mongoshell and see whether the results tally?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.