Updating an attribute of an object located within array of a collection


#1

Hi there-

I am attempting to update an attribute of an object located within an array of a collection, but I seem to be having a little trouble.

There is a collection of apps, and within the apps, there is an array of reviews. I am trying to update a “delete” boolean attribute within the review object.

Unfortunately, it looks like I have an error somewhere in my Apps.update query. Anyone able to please help point me in the right direction?

Thanks!

Apps.update(doc._id, { 'reviews._id': reviewId { '$set' { delete: true } } } );

UPDATE
Perhaps I am on the right track with the code below, but I am getting an error "untrusted code may only update documents by ID. This confuses me as I am updating both the Apps document and reviews object by ID.

Apps.update({ '_id': doc._id, 'reviews': reviewId }), { '$set': { 'deleted': true }};

UPDATE #2

To anyone following my little journey here, I think I’ve found the better way to access which review I am trying to edit with @index, instead of doing an update for the app by id, then trying to grab the review by reviewId.

I can successfully grab the index of each of my reviews within the app object, however, any data associated with the specific review is gone whenever I do it. It might be because I am incorrectly using @index, so here’s what I have:

{{#each reviews}}
    <br> {{#if Template.subscriptionsReady}} {{> Review index=@index}} {{else}}
            <p>Loading...</p>
            {{/if}} 
{{/each}}

When index=@index is removed from the Review template handlebars, the data is available. With index=@index within the handlebars, the data is simply missing from the template when I call attributes, example is {{content}} of the review shows when @index is not there, but with it, it’s simply blank.

Would anyone be able to help me position this the correct way?

Thank you all once again.


#2

Not to derail you from solving the problem at hand, but why not have a separate collection for the reviews?

Regarding the index issue – when you pass index=@index into the template, you are resetting the data context. You can do the following to keep the data context and make your index accessible:

{{#each reviews}}
  {{#let index=@index}}
    {{> Review}}
  {{/let}}
{{/each}}

#3

Thanks! This does seem to work, meaning the data IS displaying as you mentioned. However, I can’t seem to access the index value from inside the Review template. Can you give me any direction on how to further do that? Simply calling {{index}} doesn’t provide the value. :frowning:

And as far as a separate Review collection. That is possible, and I have tried that, but I was honestly running into problems connecting the review ID with the associated app ID and actually calling the data to display it at all. I was attempting to store the reviewID within the specific app object as well as the appID within the review object. But, honestly, I was trying to do this with Angular2 and it was causing me all sorts of headache and seemed to be out of my grasp. Would this be an easier feat with standard Meteor logic?

Thanks again.


#4

Actually, I think you’re right with the reviews collection. Thinking it through, it will probably be easier overall to have a reviews collection published, along with an apps collection. I can then subscribe as necessary on each template and pass / insert the correct ID’s as needed.

I’m giving it a whirl!


#5

Just my two cents, but I’d store the app in an app collection, and then store all of the reviews in a reviews collection, with each review having an appId field. Then in your subscription, just subscribe to the app (by _id), and subscribe to the reviews (by appId). Then you could use something like:

<template name="myApp">
  {{#each app}}
    {{#each review _id}}
      <!-- review stuff -->
    {{/each}}
  {{/each}}
</template>

and:

Template.myApp.helpers({
  app () {
    return Apps.find();
  },
  review (id) {
    return Reviews.find({ appId: id });
  }
});

#6

Ha. That’s exactly what I thought through. :slight_smile: I’m moving in that direction now.


#7

Right on. Post back if you run into anything. Good luck!


#8

Hey there! Got the reviews collection up and running and my function IS correctly saving the appID within the review object.

However, I’m having difficulty saving the review.id within the app object. Can you take a look and help, if possible? :slight_smile:

Template.AppSingle.onCreated(function() {
    var self = this;
        self.autorun(function() {
        self.subscribe('apps');    
    });
});

Template.AppSingle.events({
    'submit .reviewInput': function(event) {
        var rating = $('#rating').data('userrating');
        data = SimpleForm.processForm(event.target);
        data.rating = rating;
        data.appId = this._id;
        Reviews.insert(data);
        Apps.findOne({id: this._id}, { $set: { "reviewId": data._id } });
    }
});

Template.AppSingle.helpers({
    app: () => {
        return Apps.findOne(this._id);
    }
});

#9

I guess my first question is – why do you need to save the review id inside the app doc?


#10

Maybe I am thinking of it wrong, then. I was thinking I’d need the review IDs within the app doc, when I call {{#each apps}} to be able to correctly reference which reviews belong to which app?


#11

Nah, you won’t need it.

If you take a look at the sample I posted above, you will see that the first #each loops through the apps.

The second #each loops through the reviews, passing the _id of the app to the helper.

The review helper I posted above will only return reviews that have an appId that matches the id passed to the helper – in this case, the _id from the app being looped through in the first each.

Does that make sense?


#12

Yes, it does! My bad for blazing through too fast. :grin:

You’ve been a great help. Thank you!