Feel expression for-loop with if-statement

I’m trying to understand how to work with for-loops using the FEEL language. What I want to do is something very simple, like for example:

for item in items
if item.primary = true
return
{
isValid: true
}

return { isValid: false }

But this does not seem to easy to do using the FEEL language, as it seems to like to return a result for each item as I understand it, which is not what I want.

Let me give a longer example which is more exactly what I am trying to do.
I have this object called “garage”:

{
  "cars": [
    {
      "car_brand": "Toyota",
      "model": "Corolla",
      "year": 2020,
      "primary": true,
      "id": "car-toyota-corolla-uuid",
      "fullName": "Toyota Corolla 2020"
    },
    {
      "car_brand": "Honda",
      "model": "Civic",
      "year": 2019,
      "primary": false,
      "id": "car-honda-civic-uuid",
      "fullName": "Honda Civic 2019"
    }
  ]
}

Then I would like to have a feel expression in Camunda Modeler that would work like:

for item in garage.cars return
  if item.primary = true then 
    if item.fullName = CarDTO.name then
      {
        isValidCar: true
      }
    else if 
      {
        isValidCar: false,
        oldCarObject: item
      }

return null

There will always just be one “primary”: true. So ideally I would like to loop through all the cars in the garage, find the one which is primary and return if that car has the same name as CarDTO.name, and then simply return that and finish. With perhaps a backup that we will return null.

How can I write an expression that will result in a single object and not an array of objects?

Hi,

You could try a filter, eg

Garage.cars[primary=true][1].fullName = carDto.name

In other words filter for the primary returning an array of size 1. Then dereference it and the attribute fullName

Regarfs

Rob

Hi @vorbrom ,

You’re absolutely right — FEEL (Friendly Enough Expression Language) in Camunda is more declarative and typically returns a list when using for ... in ... return, which makes “early return on match” logic a bit tricky since FEEL isn’t imperative.

You can still achieve your goal using a filter + first match + conditional mapping.

You can try something like below:

FEEL expression:

let primaryCar = first(filter(garage.cars, c -> c.primary = true)) in
  if primaryCar != null then
    if primaryCar.fullName = CarDTO.name then
      { isValidCar: true }
    else
      { isValidCar: false, oldCarObject: primaryCar }
  else
    null
  • filter(garage.cars, c -> c.primary = true)
    ➜ Gives a list of primary cars (you said there’s always only one)
  • first(...)
    ➜ Gets the actual car object, not a list
  • Then we do a conditional check on the fullName against CarDTO.name
  • If no primary car exists, it returns null

This will give you a single object (not a list) that matches the logic you described.