Method to update users role is giving an error when using Collection2 package

Here is my method:

removeRole: function(role) {
check(role, String);
  var user = Meteor.user();
  if (!user || ! AccountsAdmin.checkForAdminAuthentication(user))
  throw new Meteor.Error(401, "You need to be an authenticated admin");

// handle non-existing role
if (Meteor.roles.find({name: role}).count() < 1 )
    throw new Meteor.Error(422, 'Role ' + role + ' does not exist.');

if (role === 'admin')
    throw new Meteor.Error(422, 'Cannot delete role admin');

// remove the role from all users who currently have the role
// if successfull remove the role
Meteor.users.update(
    {roles: role },
    {$pull: {roles: role }},
    {multi: true},
    function(error) {
        if (error) {
            throw new Meteor.Error(422, error);
        } else {
            Roles.deleteRole(role);
        }
    }
);
},

Here is the error I receive when looking at the call in Kadira:

message: After filtering out keys not in the schema, your modifier is now empty 
stack:
Error: After filtering out keys not in the schema, your modifier is now empty
at [object Object].doValidate (packages/aldeed_collection2-core/lib/collection2.js:282:1)
at [object Object]._.each.Mongo.Collection.(anonymous function) [as update] (packages/aldeed_collection2-core/lib/collection2.js:83:1)
at [object Object].Meteor.methods.removeRole (packages/accounts-admin-ui-bootstrap-3/server/methods.js:86:1)

Line 86 of that methods.js is “Meteor.users.update” in the code above. When trying to debug this using breakpoints it appears this is where the error is happening as well.

I am using this package to help with the user management UI that I am creating, although I have did some customizing to it. I have also tested this on a different version of my project for troubleshooting and I have found that it works when I don’t use the Collection2 package/my custom schema. I’m not too sure what the exact issue is, but I’m guessing I need to add something to the schema but I’m not sure what…

Here is my custom schema setup:

Schema = {};

Schema.UserProfile = new SimpleSchema({
userProfile: {
    type: Object
},
'userProfile.firstName': {
    type: String,
    optional: true,
    label: "First Name"
},
'userProfile.lastName': {
    type: String,
    optional: true,
    label: "Last Name"
},
'userProfile.birthday': {
    type: Date,
    optional: true,
    label: "Date of Birth"
},
'userProfile.contactEmail': {
    type: String,
    optional: true,
    label: "Email"
},     
'userProfile.gender': {
    type: String,
    allowedValues: ['Male', 'Female'],
    optional: true,
    label: "Gender"
},
'userProfile.address': {
    type: String,
    optional: true,
    label: "Address"
},
'userProfile.city': {
    type: String,
    optional: true,
    label: "City"
},
'userProfile.stateProvince': {
    type: String,
    optional: true,
    label: "State/Province"
},
'userProfile.postalCode': {
    type: String,
    optional: true,
    label: "Postal Code"
},
'userProfile.phoneNumber': {
    type: String,
    optional: true,
    label: "Phone Number"
},
userProfilePayment: {
    type: Object
},
'userProfilePayment.paymentEmail': {
    type: String,
    optional: true,
    label: "Payment Email"
},
'userProfilePayment.address': {
    type: String,
    optional: true,
    label: "Address"
},
'userProfilePayment.city': {
    type: String,
    optional: true,
    label: "City"
},
'userProfilePayment.stateProvince': {
    type: String,
    optional: true,
    label: "State/Province"
},
'userProfilePayment.postalCode': {
    type: String,
    optional: true,
    label: "Postal Code"
},
'userProfilePayment.phoneNumber': {
    type: String,
    optional: true,
    label: "Phone Number"
},

});

Schema.User = new SimpleSchema({
username: {
    type: String,
    // For accounts-password, either emails or username is required, but not both. It is OK to make this
    // optional here because the accounts-password package does its own validation.
    // Third-party login packages may not require either. Adjust this schema as necessary for your usage.
    optional: true
},
emails: {
    type: Array,
    // For accounts-password, either emails or username is required, but not both. It is OK to make this
    // optional here because the accounts-password package does its own validation.
    // Third-party login packages may not require either. Adjust this schema as necessary for your usage.
    optional: true
},
"emails.$": {
    type: Object
},
"emails.$.address": {
    type: String,
    regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
    type: Boolean
},
createdAt: {
    type: Date
},
profile: {
    type: Schema.UserProfile,
    optional: true
},
// Make sure this services field is in your schema if you're using any of the accounts packages
services: {
    type: Object,
    optional: true,
    blackbox: true
},
// Add `roles` to your schema if you use the meteor-roles package.
// Option 1: Object type
// If you specify that type as Object, you must also specify the
// `Roles.GLOBAL_GROUP` group whenever you add a user to a role.
// Example:
// Roles.addUsersToRoles(userId, ["admin"], Roles.GLOBAL_GROUP);
// You can't mix and match adding with and without a group since
// you will fail validation in some cases.
roles: {
    type: Object,
    optional: true,
    blackbox: true
},
// In order to avoid an 'Exception in setInterval callback' from Meteor
heartbeat: {
    type: Date,
    optional: true
},
// Added to work with mizzao:user-status
status: {
    type: Object,
    optional: true,
    blackbox: true
}
});

Meteor.users.attachSchema(Schema.User);

Meteor.users.allow({
// NOTE: The client should not be allowed to add users directly!
insert: function(userId, doc) {
    // only allow posting if you are logged in
    console.log("doc: " + doc + " userId: " + userId);
    return !! userId;
},

update: function(userId, doc, fieldNames) {
    // only allow updating if you are logged in
    console.log("doc: " + doc + " userId: " + userId);
    // NOTE: a user can only update his own user doc and only the 'userProfile' and 'userProfilePayment' field
    return !! userId && userId === doc._id && _.isEmpty(_.difference(fieldNames, ['userProfile, userProfilePayment'])); 
},
/* NOTE: The client should not generally be able to remove users
remove: function(userID, doc) {
    //only allow deleting if you are owner
    return doc.submittedById === Meteor.userId();
}
*/
});

I’m fairly new to Meteor so any help would be greatly appreciated!

In your schema definition you have roles set to be type Object:

roles: {
  type: Object,
  optional: true,
  blackbox: true
},

In your method however you’ve wired things up so that the passed in role should be a String. When you then try to update the users collection, the passed in String based role doesn’t match your schema’s Object based role, so it is stripped (which is why you’re getting a message saying your modifier is now empty). You should consider either modifying your schema to gives roles a type of [String], or adjust your method if you really want to use Object based roles (role groups).