Mongo Update Array with Checkbox


#1

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.


#2

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.


#3

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


#4

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.


#5

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

Thank you.


#6

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.