Mongo Update Array with Checkbox

First off, I’d like to say I’m a noob and I have only recently started making “bigger” apps with Meteor. I’m having a problem updating an array value inside a Mongo collection in Meteor. Here is an example document:

{
    "_id" : "2rhqEN8yjLf8kReJn",
    "name" : "John",
    "age" : 34,
    "userId" : "AE7iW5ZuByvpMCKd6",
    "chapters" : [
            {
                    "id" : "qwmkKJb4Zbk6svGHh",
                    "name" : "chapter1",
                    "done" : false
            },
            {
                    "id" : "vxnEwtJpxNnK5xaZm",
                    "name" : "chapter2",
                    "done" : false
            },
            {
                    "id" : "nqX5gbpCSmujNEyJm",
                    "name" : "chapter3",
                    "done" : false
            }
}

I basically have an event on a checkbox to change (update) that “done” value on click. The problem is, I’ve tried many different methods and none have worked right so far. Here is my current code:

Meteor.methods({
  toggleCheckbox: function(id, checkid, done) {
  Students.update(
   { _id: id, "chapters.id": checkid},
   { $set: { "chapters.$.done" : done } }
  );
 }
});

As you can see I’m using a method. In case you need it, here is the event:

Template.student.events({
  'change #chapterComplete': function() {
  var data = Template.instance().data;
  Meteor.call('toggleCheckbox', data._id, this.id, !this.done);
  }
});

I have spent way too long on this, and I feel like it’s some small mistake I’m making somewhere. Any help would be greatly appreciated.

The obvious stuff first - have you logged the values passed to the method? Within an event handler, this in particular may not be as you expect.

Yes, Template.instance().data returns the specific student ID. And this.id returns the chapter id.

Your code works for me. However, I had to correct an error in your document object first - you have not closed the chapters array. It should look like:

{
  "_id": "2rhqEN8yjLf8kReJn",
  "name": "John",
  "age": 34,
  "userId": "AE7iW5ZuByvpMCKd6",
  "chapters": [
    {
      "id": "qwmkKJb4Zbk6svGHh",
      "name": "chapter1",
      "done": false
    }, {
      "id": "vxnEwtJpxNnK5xaZm",
      "name": "chapter2",
      "done": false
    }, {
      "id": "nqX5gbpCSmujNEyJm",
      "name": "chapter3",
      "done": false
    }
  ]
}

I then ran this (hardcoded) update on the server from your method:

Students.update({_id: "2rhqEN8yjLf8kReJn", "chapters.id": "vxnEwtJpxNnK5xaZm"},
 {$set: {"chapters.$.done": true}});

Which set the correct done flag to true.

Alright. I’m at work right now, but as soon as I get home, I’ll try your solution.

Thank you.

It seems like that was only an error in my post. I closed off the array in my code. However this may be the problem but I don’t know any better way.

Students = new Meteor.Collection('students');

Students.before.insert(function (userId, doc) {
  doc.chapters = [
    {id: Random.id(), name: "chapter1", done: false},
    {id: Random.id(), name: "chapter2", done: false},
    {id: Random.id(), name: "chapter3", done: false},
    {id: Random.id(), name: "chapter4", done: false},
    {id: Random.id(), name: "chapter5", done: false},
    {id: Random.id(), name: "chapter6", done: false},
    {id: Random.id(), name: "chapter7", done: false},
    {id: Random.id(), name: "chapter8", done: false},
    {id: Random.id(), name: "chapter9", done: false},
  ];
});

Basically what this is doing is it’s adding this array to any new document that gets created (in this case, as soon as a new student is created). I was wondering if there was a better way to do this (add array with static data on document create). Solutions with the use of a package are welcome.

Thanks again.