How to update single component in User?

System Information
  • Strapi Version: 3.4.6

I created a component called ‘userAchievements’ under collection ‘internal’. I added that component to the User content type with field name ‘achievements’. I do see that I have that component on the User object:

achievements: {
  someAchievement: false,
  anotherAchievement: false,
  _id: some1234,
  __v: 0,
  id: 'some1234'
}

Now I created a custom service to update the user (as I will need to update him automatically when he reaches certain achievements) in ‘api/user/services/user.js’:

module.exports = {
  updateUser: async (id, data) => {
    return await strapi.query('user', 'users-permissions').update({ id }, data);
  }
}

And this is how I tried to call it from another service:

await strapi.services.user.updateUser(userId, {
    'achievements.hasCompletedFirstReview': true
})

I didn’t get any errors, but the component wasn’t updated. Then I tried also this:

await strapi.services.user.updateUser(userId, {
    __component: 'user-achievements',
    id: ctx.state.user.achievements.id,
    hasCompletedFirstReview: true
})

Same result - no error, no update. I tried to change __component to ‘internal.user-achievements’ - also same result.

So is there a way to update a component on the User? What am I doing wrong?

I was finally able to solve it, maybe someone will find it useful.
First of all I wrote the updateUser method wrong. Here’s the correct one:

module.exports = {
  updateUser: async (id, data) => {
    return await strapi.query('user', 'users-permissions').update({ id }, {data});
  }
}

And then I called it wrong. Here’s how I do it now:

await strapi.services.user.updateUser(userId, {
  achievements: {
    id: ctx.state.user.achievements.id,
    hasCompletedFirstReview: true
  }
})
1 Like

I think I was too fast to judge… For some reason it worked only once - I tried to reset the updated value and run the scenario again and the value wasn’t updated.

Take a look at the components section.

You should always specify the ID of the component that you want to update. Otherwise, it will be deleted and recreated. So the ID of the new component will change.

Is that a single component or a repeatable one?


In this example, you tried to update the User’s fields and not the component.


That example that you provided in the last post looks ok. It should work properly if your ctx.state.user.achievements.id exists.

await strapi.services.user.updateUser(userId, {
  achievements:{
      id: ctx.state.user.achievements.id,
      hasCompletedFirstReview: true
  }
});

Are you calling the strapi.services.user.updateUser service from the controller? Because services do not have access to the ctx object. Only you provide it to them. Can you try to output the ctx.state.user.achievements.id before calling the updateUser service?

@sunnyson

First of all, thank you very much for your reply!

The component is a single component. Basically I’m trying to group every possible achievement the user may have in a component instead of heaving separate fields in the User model.

That’s very confusing… I thought I’m updating the component’s fields in the User model.

Yes, it is being called from a controller and yes, ctx.state.user.achievements.id can be outputted before I call the updateUser service.

Last time I tried to run this scenario it worked again. I’ll try to reset the data and run the scenario again to see if it still works.

Thanks for sharing, that works by me

The link to “component” section that you posted (https://strapi.io/documentation/developer-docs/latest/concepts/models.html#components) does not work. It leads to 404.
Could you please update with the working link?