Refetch doesn't work in loop

Hi there,

I am trying to get all optionGroups with a given code in the array.
The refetch request runs only once and I cannot understand the reason.
request string defined as :

const queryOGs = {
    result: {
      resource: "optionGroups",
      params: ({ code }) => ({
        fields: ["id", "code", "options[id,name,code]"],
        filter: "code:like:" + code,
      }),
    },
  };

initial call:

const ogList = useDataQuery(queryOGs, {
    variables: { code: "RRR11111111" },
    onComplete: (response) => {
        if (response.result.optionGroups.length> 0)
          setOGList(response.result.optionGroups[0].options);
    },
  });

and refetch calls inside the loop:

 for (var j=0; j < childNode.length; j++){
   ogList.refetch({ code: childNode[j].value });
      if (OGList.length)
          OGList.map((e) => {
              some operations...
           })
}

It runs only once and the rest I can’t get any results…

Thank you
Regards,
Ulanbek

I think the reason is because in the loop when using refetch it’s not given the sufficient time to get the data and then immediately the next line of code is executed.

Could you try:
await ogList.refetch({ code: childNode[j].value }); ?

I think the reason is because const ogList is running even before the refetch. When using useDataQuery, and you don’t want it to run immediately, you need to use the lazy option which will stop it from running until you use the refetch(source)

const { loading, error, data, refetch } = useDataQuery(queryOGs, {
    variables: { code: "RRR11111111" },
    onComplete: (response) => {
        if (response.result.optionGroups.length> 0)
          setOGList(response.result.optionGroups[0].options);
    },
    lazy: true,
});

Hi @Gassim

@Gassim , I understand this is async call and created following:

const ogRefetch = async (param )=>{
    await ogList.refetch({ code: param });
    if (ogList.response.result.optionGroups.length> 0){
      setOGList(response.result.optionGroups[0].options);
    }
  }

and still have not succeeded…

Great, did you try to add the ‘lazy’ option as well?

is it possible to console.log all of your code or use debugging to see how the whole thing flows…

Hi @Ulanbek: thanks for this question.

Why you have the problem
In general, async promises will not work well in a loop as the order of the responses will be unpredictable. In the case here, you’re using the refetch (returns a promise) and combining it with a React state variable, so it would be very hard to get everything aligned. In addition, our implementation of refetch tries to prevent unnecessary re-firing of queries, so you may run into issues with useDataQuery trying to not re-execute needlessly.

Solution with rewriting queries
In general, it can be easiest to see if you can restructure your query in a simpler way to avoid the complexities of multiple async promises. In your example, it looks like you want to filter optionGroups based on code. You might want to consider doing one api query where you filter by multiple codes. You can make filter conditions non mutually exclusive by adding rootJunction=OR (for example https://play.im.dhis2.org/dev/api/dataElements?fields=id,name,code&filter=name:like:ANC&filter=name:ilike:ARI&rootJunction=OR)).

You can find information on rootJunction here: Metadata - DHIS2 Documentation

Possible solution for multiple queries
If you cannot restructure your query definition into one query, you can still update your code to handle multiple requests.

The most common way to handle multiple promises is promise.all. You can use this in if you process your queries with the engine returned from useDataEngine. Then you can do something like const [resultOne, resultTwo] = Promise.all(engine.query(QUERY_ONE), engine.query(QUERY_TWO))

Here is an example in a real app (the Data Quality Annual Report App, which was developed by HISP RW/UiO): who-data-quality-annual-report/src/components/annual-report/section4/useSectionFourData.js at 8aa2a8c181e7ccedc679b87f0236a0d4b4a78cf2 · hisprwanda/who-data-quality-annual-report · GitHub

1 Like

Thank you @tzemp ! I’ll try to follow your suggestion. I am aware of the problem with promises and updating REACT states :frowning: No flexibility

Regarding why I need to rerun multiple queries: I need to filter optionGroups by code, which I have tried to filter by passing array of filters, which didn’t worked :frowning:

Therefore I decided to run multiple refetching for each code separately.

If I will not succeed than will try to use direct API requests, which I think will work much better and faster

Thank you and will keep you updated

2 Likes

Regarding why I need to rerun multiple queries: I need to filter optionGroups by code, which I have tried to filter by passing array of filters, which didn’t worked :frowning:

I think the inclusion of rootJunction=OR (as mentioned above) would help you pass the multiple filter conditions in a single query, e.g. https://play.im.dhis2.org/dev/api/dataElements?fields=id,name,code&filter=name:like:ANC&filter=name:ilike:ARI&rootJunction=OR

2 Likes

Hi @tzemp

Your suggestions rootJunction=OR did magic. So now I can filter as much orgUnits or optionGroups as I need :slight_smile:

Thank you

Regards,
Ulanbek

1 Like