DEV Community

Cover image for Power Apps- Patch vs Update & Collect
david wyatt
david wyatt Subscriber

Posted on • Edited on

Power Apps- Patch vs Update & Collect

Every good programming language has many ways to do the same task, from all the different loops to manipulating arrays, there is no one version of the truth. Admittedly they all have the features and strengths, but they overlap so much that they become interchangeable. And though in one case one solution might be optimum, developer style will always carry more.

The Power Platform is pushing Power FX as its own code language, and to keep in step it has multiple ways of doing the same thing. The most obvious is dealing with data sources and collections (arrays). As with most low code developers, I learned from doing not from training, so was surprised to learn there was not just Patch to update data sources. So I thought I would dive into the different ways and find the best.

Below are all the different ways to modify arrays, there are actually 3 different arrays in Power Apps, datasources, collections and variables. That's right, you can save an array in a variable, why? I have no idea.

Formula Description Scope
Patch Modify / Create Data/Coll
Update Replace (like PUT) Data/Coll
UpdateIf Modify by condition Data/Coll
SubmitForm Modify / Create Data/Coll
Collect Create All
ClearCollect Clear & Create Coll/Var
Remove Remove record Data/Coll
RemoveIf Remove by condition Data/Coll
table Create Var

Note that if you Collect or ClearCollect a var it works but also creates an empty collection with same name

So as you can see, they all have their own features and reasons for existing, but there is a lot of overlap, especially for the main use cases:

1. Modify Record

So if you wanted to update a record in either a datasource or collection (it isn't possible to update variable) you have 4 options.

Patch(dummyData,
    LookUp(dummyData,ID=1)
,
    {Title:"Num1",number:1}
)
Enter fullscreen mode Exit fullscreen mode
UpdateIf(dummyData,{Title:"Num1",number:1})
Enter fullscreen mode Exit fullscreen mode
Update(dummyData,
    LookUp(dummyData,ID=1)
,
    {Title:"Num1",number:1}
,
    first
)
Enter fullscreen mode Exit fullscreen mode
SubmitForm(dummyDataForm)
Enter fullscreen mode Exit fullscreen mode

The most simple way has to be SubmitForm (that's why it is pushed in templates), but for me the limitations of forms layouts make it not suitable for most cases (especially now as we have error handling outside of forms). So lets ignore it and look at the rest.

As you can see, Update and Patch are almost the same, with the difference the same difference between PATCH and PUT (Update replaces the record, so all fields need to be included, else they will be null). So I would say Patch supersedes Update in most cases.

But then there is UpdateIf, which doesn't require a record (saving a lookup/filter). So to me it is the most simple to use, as long as you have a GUID field you can use (unless you want to do bulk updates to same condition, which UpdateIf for is great for).

Except that's not exactly true, see if you have a GUID you can use Patch without a lookup, as we don't need a full record to identify it. Check this out:

Patch(dummyData,{ID:1},{Title:"Num1",number:1})
Enter fullscreen mode Exit fullscreen mode

works too, so we don't need that lookup.

Bulk updates

Patch can also do bulk updates through a collection. So if I had pulled a datasource to a collection (colData in below example), updated the collection, then patched the datasource Patch is the way to go

Patch(dataSource,ShowColumns(colData,"ID","Title"))
Enter fullscreen mode Exit fullscreen mode

vs

ForAll(colData,
    UpdateIf(dataSource,
        ID=ThisRecord.ID
    , 
        {Title:ThisRecord.Title,number:ThisRecord.number}
    )
)
Enter fullscreen mode Exit fullscreen mode

I use ShowColumns because we cant Patch the readOnly fields we get from SharePoint Lists, though would be better to move that to the Collect.

Patch can also mix and match, so if you have a collection or Table with Blank GUID, it will create a record for the record, but modify the other records

colData=
    {ID:Blank(),number:34,Title:"Num34"}
,
    {ID:1, number:1,Title:"Num1.1"}
Enter fullscreen mode Exit fullscreen mode
Patch(dummyData,colData)
Enter fullscreen mode Exit fullscreen mode

Update can bulk, but only if the matches is set to All and there is no GUID in the array. UpdateIf will if there are multiple matches to the condition.

So each have their own bulk use, but Patch is the most useful.

2. Create Record

To create a record we have 3 main ways (ClearCollect will be represented as Collect):

Collect(dummyData,{Title:"Num1",number:1})
Enter fullscreen mode Exit fullscreen mode
Patch(dummyData,
    Defaults(dummyData)
,
    {Title:"Num1",number:1}
)
Enter fullscreen mode Exit fullscreen mode
Set(varDummyData,
    Table({Title:"Num1",number:1},{Title:"Num2",number:2})
)
Enter fullscreen mode Exit fullscreen mode

I'm still at a loss why anyone would store an array in a variable, it can't be modified, record deleted and adding causes bugs. So I'm going to ignore it too.

So Patch requires the Defaults(dummyData) to show its a create instead of modify, giving Collect the advantage in simplicity. So win for Collect, or is it?

Did you ever wonder what the point of the Table function was, it seems it is only useful for saving arrays in variables. But used with Patch it can incredibly useful, using Table we can simplify Patch, by creating a single row array

Patch(dummyData,Table({Title:"Num1",number:1}))
Enter fullscreen mode Exit fullscreen mode

So we can drop the Defaults(dummyData) and make it a lot simpler. Although Collect is probably best, Patch is very close, and it has the advantage of not creating a Collection if it doesn't exist, a kind of explicit check to make sure you don't accidentally create a new collection.

Bulk updates

Shown by the Table function, you can Patch bulk create data (as above you can even mix and match with modify).

Patch(dummyData,
    Table(
        {Title:"Num1",number:1}
    ,
        {Title:"Num2",number:2}
    )
)
Enter fullscreen mode Exit fullscreen mode

Creates 2 new records (you can also change to another collection instead of using table, just make sure it doesn't have a GUID field or at least Blank GUID).

Patch(dummyData,  
    Table(
        {ID:Blank(),Title:"Num1",number:1}
    ,
        {ID:Blank(),Title:"Num2",number:2}
    )
)
Enter fullscreen mode Exit fullscreen mode

Collect by its essence is bulk, as it requires 2 arrays, so it is again simpler, but its interesting to see Patch is very similar.

3. Delete Record

Good news, removing/deleting record is a lot more simple, with just options, Remove and RemoveIf. Which kind of mirror Update and UpdateIf.

Remove(dummyData,LookUp(dummyData,ID=1))
Enter fullscreen mode Exit fullscreen mode

and

RemoveIf(dummyData,ID=1)
Enter fullscreen mode Exit fullscreen mode

So again RemoveIf looks like the best option, but you can use the Patch trick to make Remove a little simpler:

Remove(dummyData,{ID:1})
Enter fullscreen mode Exit fullscreen mode

Also I would say Remove is useful with Gallerys/DataTables, as you can use the Selected record for the record

Remove(dummyData,Gallery.Selected)
Enter fullscreen mode Exit fullscreen mode

Bulk updates

Both can bulk remove, by using Table or another collection for Remove:

Remove(dummyData,Table({ID:1},{ID:2}))
Enter fullscreen mode Exit fullscreen mode

and by all the values that match the condition. Though as with Update, the ability to selectively bulk is more useful.

So now looking back it feels like there really isn't a best way, just a right way for you. From a performance side they are all pretty much equal and even the length of the code is marginal once optimised.

For me I've got into the habit of Collect for collections, and Patch for all modify and create in data sources. Remove for everything. Though I think the strengths of the Ifs (Update and Remove) mean I will look at using them more in the future.

But as always, that's just my way, and I want to be careful I don't make my code hard to follow with inconsistencies.

Top comments (4)

Collapse
 
adedaporh profile image
Daporh 👨🏿‍💻

I'm still at a loss why anyone would store an array in a variable, it can't be modified, record deleted and adding causes bugs. So I'm going to ignore it too.

I use variables for arrays, if the arrays are readonly. This is great for lookup tables. It's great to have a restricted version of array variables to reduce bugs.

I generally try to avoid collections if I'm not doing CRUD operations on the data, which I find to be a lot more common than I thought at first.

If I realise that an array needs the other CRUD operations I just simply update it to a collection.

Collapse
 
wyattdave profile image
david wyatt

Fair point, I just like consistency of collections for array, makes development easier. I've never had an issue with the need for consts, but might make sense in large complex apps

Collapse
 
adedaporh profile image
Daporh 👨🏿‍💻

Speakimg of consts, it also makes it easier to transition to named formulas for better performance.
If only named formula tables were not so buggy 🫠

Thread Thread
 
wyattdave profile image
david wyatt

That's a great point, as there is no collections in named formulas it would be worth it for performance improvements (like you said when not so buggy). Might have to update the blog now 😀