[CSHARP-292] There should be a way to join several UpdateBuilder instances into a complete update expression (IMongoUpdate) Created: 31/Jul/11  Updated: 02/Apr/15  Resolved: 05/Aug/11

Status: Closed
Project: C# Driver
Component/s: Feature Request
Affects Version/s: None
Fix Version/s: 1.2

Type: Improvement Priority: Minor - P4
Reporter: Roman Kuzmin Assignee: Robert Stam
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Backwards Compatibility: Fully Compatible

 Description   

For example a new constructor of UpdateDocument: UpdateDocument(IEnumerable<UpdateBuilder>).

UpdateBuilder chains do not cover all practical scenarios well. My application creates update pieces for each field separately. Pseudo code:

UpdateBuilder Method1()

{ return Update.Set("filed1", value1); }

UpdateBuilder Method2()

{ return Update.Set("filed2", value2); }

...

As a result, in a method that calls Method1, Method2, ..., MethodN I have a collection of update expressions, one per a field. The driver does not provide an easy way to join these pieces into a single update expression to be used in Update() methods. Instead, we have to create a starter empty UpdateBuilder, send it to all methods, and methods have to be a bit more complex:

UpdateBuilder Method1(UpdateBuilder builder)

{ return builder.Set("filed1", value1); }

UpdateBuilder Method2(UpdateBuilder builder)

{ return builder.Set("filed2", value2); }

...

""""" Real scenario: it shows that even Method(UpdateBuilder) approach is not enough for all """""

In fact, my application is a PowerShell module designed for MondoDB + C# driver.
In scripts I would like to be able to perform commands like this:

Update-Data $collection $query @(
Set-Value filed1 value1
Set-Value filed2 value2
Set-Value filedN valueN
)

The last argument of Update-Data cmdlet (it calls Update() on $collection) is a collection of update expressions produced by one or more calls of the Set-Value cmdlet (gets an update expression for a single field).

But this desirable code is now not supported due to lack of a proposed driver method. I cannot even use Method(UpdateBuilder) approach because the expression @(..) is evaluated before the call to Update-Data and there is no chance to initiate a starter UpdateBuilder to be sent to Set-Value cmdlets even implicitly (say, as a hidden internal variable shared between Set-Value calls).

Instead, I have to make the Set-Value cmdlet to accept optional UpdateBuilder input via pipeline. So that I have to emulate UpdateBuilder chains in a peculiar way. And the code above right now actually has to look like this:

Update-Data $collection $query ( `
Set-Value filed1 value1 |
Set-Value filed2 value2 |
Set-Value filedN valueN
)

So that the first call to Set-Value initiates a starter UpdateBuilder and sends it to other Set-Value-s. The required UpdateBuilder chain is emulated.

Well, it is not that bad and the job is done. But it is not pretty either:

*) Pipelines (|) are basically expensive in PowerShell and better be avoided
*) Syntax is not so easy and neat like it could be (version 1 is much better)
*) It all gets more difficult if a script wants to call these Set-Value in different places, collect results in some $updates variable (a collection) and then only to call:

Update-Data $collection $query $updates

""""""""""

Of course, I can go to lower level and do that $set, etc. things on my own. But I think the purpose of the driver is to do such low level jobs and let users to concentrate on their application code instead. Ideally, a user of C# driver should not have to know MongoDB query/update expression syntax details.



 Comments   
Comment by Roman Kuzmin [ 06/Aug/11 ]

Robert,

Thank you. This is exactly what I was asking for. As a result, I got rid of my extra helper class. All now works in simple and natural way.

NB: It was needed for C# API in the first place. PowerShell was mentioned just as an example of a scenario that triggered the issue. The new Combine() method I actually consume in C# (but for PowerShell, yes).

Comment by Robert Stam [ 05/Aug/11 ]

The static method Update.Combine combines a variable number of UpdateBuilders into one single new UpdateBuilder. The instance method UpdateBuilder.Combine combines one other UpdateBuilder into an existing UpdateBuilder.

I assume the static method will do what you wanted to do in Powershell. Let me know if it does not.

Comment by Roman Kuzmin [ 31/Jul/11 ]

OK, I have found a way to make desirable syntax to work in PowerShell scripts. But this is rather rocket science comparing to how easy it could be instead if we are able to join update expressions . So the ticket suggestion is still valid.

Here it is, just in case if anybody interested.

=1=
I introduced a class:
public class UpdateField
{
public Func<UpdateBuilder, UpdateBuilder> Build

{ get; private set; }

public UpdateField(Func<UpdateBuilder, UpdateBuilder> build)

{ Build = build; }

public override string ToString()

{ return Build(new UpdateBuilder()).ToString(); }

}

=2=
Cmdlets Set-Value, etc. now emit not UpdateBuilder objects (as it used to be straightforward) but new UpdateField objects with attached delegates that do actual calls to Set, Inc, Push, Pull, etc. (more convoluted).

=3=
Cmdlet Update-Data (that calls Update()) joins one or more input UpdateField objects by creating an UpdateBuilder and calling Build on every UpdateField, thus, chaining them, as far as chaining is the only possible way to build a complex update expression.

All in all, now I can do this in PowerShell:

Update-Data $collection $query @(
Set-Value filed1 value1
Set-Value filed2 value2
Set-Value filedN valueN
)

Or even more dynamic (with true chain/pipeline approach that would not be so easy):

Update-Data $collection $query @(
Set-Value filed1 value1
if (something)

{ Set-Value filed2 value2 }

Set-Value filedN valueN
)

Generated at Wed Feb 07 21:36:24 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.