How to update object item in array?

Suppose i have:

"companies": [
      {
        "companyName": "Test1506",
        "companyId": "test1506_090bee58-c518-4791-b8c8-5de7eefec10b",
        "role": "PARTNER"
      },
      {
        "companyId": "somecompanyname_34f64628-a8f4-4e2d-969f-da45e8a04966",
        "companyName": "somecompanyname",
        "role": "DRIVER"
      },
      {
        "companyName": "somnium",
        "companyId": "somnium_6a8b779f-824d-41bd-83e6-bf1d146fa1e9",
        "role": "ADMIN"
      }
    ],

and i want change any field in one of object?

now i need complete stages:

  1. Get document and select “companies” fileld
  2. Filter needed companies in two variables “updateInCompany”, “restCompanies”
  3. Then merge in result companies:
q.Union(
    q.Var('restCompanies'),
    [q.Merge(q.Select([0], q.Var('updateInCompany')), { role: "ADMIN" })],
)
  1. Then update document with new “companies” field

The question is are exists another more pretty way to update field in object which in array?
Or which way is the best practice in such a case?

May be i can use index like this? (this not works):

{
    name: 'user_companies_by_id',
    source: q.Collection('users'),
    serialized: true,
    terms: [
      { field: ['ref'] },
      { field: ['data', 'companies', 'companyId'] },
    ],
  }

Arrays are stored immutably as the whole array, and individual items can not be edited in place. To update one item, you must make your changes and store the whole thing again. The steps you shared to update the array are a good example of how you can do that.

You can, in fact, index on ['data', 'companies', 'companyId'] as you have shown. Unfortunately, the index will return the user Ref, so you still have the same issues trying to update and store an immutable array.

If you need to update individual objects in an array, you may be better off putting those objects in a separate Collection. Fauna Document-Relational features mean that you can store and access the relationships efficiently.

It looks like you have a many-to-many relationship between users and companies, and those relationships have properties (i.e. that role field). You could store the relationships in a link-table Collection, using Indexes to traverse from users to companies and vice-versa.

Example

User and company Documents:

Create(Collection("users"), {
  data: {
    name: "Paul"
    // no company info required
  }
})
Create(Collection("company"), {
  data: {
    name: "Test1506",
    companyId: "test1506_090bee58-c518-4791-b8c8-5de7eefec10b"
  }
})

A “link” Document that contains Refs to the user and company, as well as other required properties:

Create(Collection("user_company_link"), {
  data: {
    user: <USER_REF>,
    company: <COMPANY_REF>,
    role: "PARTNER"
  }
})

Indexes to traverse from users and companies to the links:

CreateIndex({
  name: "user_company_link_by_user",
  source: Collection("user_company_link"),
  terms: [
    { field: ["data", "user"] }
  ],
  values: [
    { field: ["data", "company"] },
    { field: ["data", "role"] },
    { field: ["ref"] },
  ],
})
CreateIndex({
  name: "user_company_link_by_company",
  source: Collection("user_company_link"),
  terms: [
    { field: ["data", "company"] }
  ],
  values: [
    { field: ["data", "user"] },
    { field: ["data", "role"] },
    { field: ["ref"] },
  ],
})

Query for all of a users companies

Map(
  Paginate(
    Match(Index("user_company_link_by_user"), <USER_REF>)
  ),
  Lambda(
    ["company_ref", "role", "link_ref"],
    {
      company: Get(Var("company_ref")),
      role: Var("role")
    }
  )
)

Thank you for reply. I understand the essence of your approach. Indeed, this is more correct from an architectural point of view. Although more verbose.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.