← Tous les articles

Filtres OData sur une source SharePoint

Dans cet article nous allons le voir toutes les subtilités des filtres au data avec les sources SharePoint, qu’il s’agisse de listes ou de bibliothèques de documents.

  1. Le protocole OData avec Power Automate
    1. Pourquoi utiliser le filtrage OData dans les actions Power Automate ?
    2. Où ajouter un filtre OData dans une action Power Automate ?
  2. Les fonctions & opérateurs
    1. Opérateurs d’équivalence
      1. eq (equal)
      2. ne (not equal)
      3. not
    2. Opérateurs de relation
      1. gt (greater than)
      2. lt (lesser than)
      3. ge (greater or equal)
      4. le (lesser or equal)
    3. Opérateurs conditionnels
      1. and
      2. or
      3. Les parenthèses
      4. Priorité dans les requêtes ambigües
    4. Fonctions
      1. startswith
      2. substringof
  3. Possibilités de filtrage par type de colonne SharePoint
    1. 🔢 Colonnes numériques
      1. ✅ ID
      2. ✅ Devise
      3. ✅ Nombre
      4. ❌ Nombre calculé
    2. 🔤 Colonnes texte
      1. ✅ Une seule ligne de texte
      2. ❌ Plusieurs lignes de texte
      3. ❌ Lien hypertexte
    3. 🗓️ Colonnes Date / heure
      1. ✅ Colonne Date
      2. ✅ Colonne Date et heure
    4. 🏷️ Colonnes choix
      1. ✅ Colonne Oui / Non
      2. ✅ Colonne Choix unique
      3. ✅ Colonne Choix Multiple
    5. 🎛️ Colonnes complexes
      1. ✅ Colonne Recherche
      2. ✅ Personne ou groupe
      3. 🔶 Emplacement
  4. 📁 Filtrage des bibliothèques de documents
    1. Nom du fichier avec extension: FileLeafRef
    2. Est un dossier : FSObjType
    3. Extension du fichier : File_x0020_Type
    4. URL Relative: FileRef
    5. Chemin d’accès au dossier : FileDirRef

Le protocole OData avec Power Automate

L’Open Data Protocol, qu’est-ce que c’est ?
En bref, c’est une manière simple et standardisée de demander et de partager des données entre différentes applications en utilisant des URL et des messages HTTP.

Plus de détails...

OData (Open Data Protocol) est une norme OASIS approuvée ISO/IEC qui définit un ensemble de bonnes pratiques pour la création et l’utilisation d’API REST. Il permet la création de services basés sur REST qui permettent aux ressources identifiées à l’aide d’URL (Uniform Resource Locators) et définies dans un modèle de données d’être publiées et modifiées par des clients Web à l’aide de simples messages HTTP.

OData aide les applications à se concentrer sur la logique métier sans se soucier des différentes approches API pour définir les en-têtes de requête et de réponse, les codes d’état, les méthodes HTTP, les conventions d’URL, les types de médias, les formats de charge utile, les options de requête, etc. Il fournit des conseils pour le suivi des modifications, la définition de fonctions/actions pour les procédures réutilisables et l’envoi de demandes asynchrones/par lots.

Plus d’infos sur Ms Learn et toute la documentation ici

</details>

Ce qu’il est important de noter, c’est que les possibilités offertes par le OData dépendent avant tout de la source avec laquelle il est utilisée, certaines fonctions supportées par une base Dataverse, ne le seront pas par une base SharePoint, il s’agit en général des fonctions qui causent des avertissement de délégation dans les applications Power Apps Canvas.

Pourquoi utiliser le filtrage OData dans les actions Power Automate ?

Alors que l’on arriverait au même résultat avec les actions “Filtrer un tableau” ou en ajoutant une condition en première étape d’un boucle ?

Tout simplement dans un soucis d’optimisation, le filtre OData permet de ne remonter que les lignes d’une table qui nous sont réellement utiles dans le flux.

L’action filtrer un tableau, nous contraint à requêter toutes les lignes d’une liste pour ensuite filtrer celles qui nous intéressent et ignorer toutes les autres. Si notre liste comporte 1000 lignes et que notre flux n’est censé opérer que sur une dizaines d’entre elles, c’est beaucoup d’énergie gaspillée.

Dans le même ordre, appliquer une boucle à l’ensemble d’une table, non filtrée, en mettant une action de condition en première étape pour déterminer si cette itération est concernée par le traitement ou non, va générer un temps de traitement exagérément long.

Où ajouter un filtre OData dans une action Power Automate ?

Dans la plupart des actions qui vont Obtenir une liste d’enregistrements, il est possible d’ajouter le paramètre avancé “Requête de filtre” :

Les fonctions & opérateurs

Les champs “Requête de filtre”, “Tri” et “Étendue de la requête” dans les actions Power Automate sont destinés à accueillir les paramètres des fonctions filter(), sort() et expand(), il ne faut donc pas écrire ces fonctions, seuls les arguments sont à fournir, lesquels peuvent traiter les fonctions suivantes :

Dans le cas qui nous intéresse, nous allons utiliser le OData avec l’API Sharepoint REST qui autorise certaines requêtes OData. A titre de comparaison, l’API Dataverse traitera plus de fonctions (+ de 60) que l’API SharePoint.

https://learn.microsoft.com/en-us/sharepoint/dev/images/spf15con_rest_queryoptionsyntax.png

Opérateurs d’équivalence

Ces opérateurs s’utilisent avec les types de données: chaînes de texte, valeurs numériques, dates, booléen. Il est possible d’évaluer les valeurs null (vide)

eq (equal)

Permet d’évaluer une égalité

Texte
Titre eq 'abcdef'
Champ numérique eq 123.45

ne (not equal)

Permet d’évaluer une différence

Texte
Titre ne 'abcdef'
Champ numérique ne 123.45

not

Inverse le résultat de l’évaluation contenue entre ()

Texte
not( Titre eq 'abcdef' and Champ numérique eq 123.45 )

Opérateurs de relation

Ces opérateurs s’utilisent avec les types de données: chaînes de texte, valeurs numériques, dates et permettent une comparaison par rapport a un seuil.

gt (greater than)

Retourne les valeurs strictement supérieures

Texte
ChampDecimal gt 123.45
ChampDate gt '2025-01-01'

lt (lesser than)

Retourne les valeurs strictement inférieures. (L’opérateur s’écrit avec un L en minuscule et non un i majuscule)

Texte
ChampDecimal lt 123.45
ChampDate lt '2025-01-01'

ge (greater or equal)

Retourne les valeurs supérieures ou égales

Texte
ChampDecimal ge 123.45
ChampDate ge '2025-01-01'

le (lesser or equal)

Retourne les valeurs inférieures ou égales. (L’opérateur s’écrit avec un L en minuscule et non un i majuscule)

Texte
ChampDecimal le 123.45
ChampDate le '2025-01-01'

Opérateurs conditionnels

Ces opérateurs permettent de combiner des évaluations et des comparaisons

and

Pour que le résultat soit retourné, les conditions combinees doivent toutes être remplies.

Texte
Titre eq 'abcdef' and Num gt 123.45

Remonte les lignes dont le Titre est “abcdef” ET dont la valeur de Num est strictement supérieure à 123,45

or

Pour que le résultat soit retourné, les conditions combinees doivent toutes être remplies.

Texte
Titre eq 'abcdef' or Num eq 123.45

Remonte les lignes dont le Titre est “abcdef” OU dont la valeur de Num est égale à 123,45

Les parenthèses

Les parenthèses permettent de lever l’ambiguïté dans les enchaînements de tests logiques. Le positionnement des parenthèses peut modifier complètement la logique du filtre :

Texte
Cas 1:
(Titre eq 'abcdef' or Num eq 123.45) and ChampDate gt 2025-01-01 
Cas 2:
Titre eq 'abcdef' or (Num eq 123.45 and ChampDate gt 2025-01-01)

Priorité dans les requêtes ambigües

Dans une requête ambigüe (sans parenthèses), le “and” aura toujours priorité sur le “or”. La requête suivante :

Texte
Titre eq 'abcdef' or Num eq 123.45 and ChampDate gt 2025-01-01

Équivaut à :

Texte
Titre eq 'abcdef' or (Num eq 123.45 and ChampDate gt 2025-01-01)

Fonctions

startswith

La fonction startswith évalue si la valeur d’une colonne texte commence par la chaîne de texte fournie. Le premier argument est la colonne, le second la chaîne à comparer.

startswith( Colonne , ‘chaîne de texte’ )

Texte
startswith( Titre , 'abcd' )

Remontera uniquement les lignes dont le Titre commence par “abcd”

substringof

La fonction substringof évalue si la valeur d’une colonne texte contient la chaîne de texte fournie. Le premier argument est la chaîne fournie, le second la colonne comportant la valeur à comparer.

substringof( ‘chaîne de texte’, Colonne )

Texte
substringof( 'abcd' ,Titre )

Remontera les lignes dont le titre contient “abcd”

Possibilités de filtrage par type de colonne SharePoint

🔢 Colonnes numériques

✅ ID

eqID eq 123L'ID est 123
neID ne 12L'ID est diffèrent de 12
gtID gt 10l'ID est > 10
ltID lt 99l'ID est < 99
geID ge 15l'ID est >= 15
leID le 60l'ID est <= 60
startswithstartswith(ID,'10')l'ID commence par '10' ( 10, 103, 1025...))
substringofsubstringof('10',ID)l'ID contient '10' (10, 210, 4106...)

Autres exemples :

Texte
L'ID est compris entre 10 et 30 inclus
ID ge 10 and ID le 30

L'ID est inférieur à 100 ou l'ID est 99999
ID lt 100 or ID eq 99999

✅ Devise

eqSalary eq 60000Salary est = 60000
neSalary ne 80000Salary est différent de 80000
gtSalary gt 50000Salary est > 50000
ltSalary lt 90000Salary est < 90000
geSalary ge 45000Salary est >= 45000
leSalary le 70000Salary est <= 70000
startswithstartswith(Salary ,'100')Salary commence par '10' ( 1000, 100500, 10200...))
substringofsubstringof('100',Salary )Salary contient '100' (110000, 45100, 81005..)
nullSalary ne nullSalary n'est pas vide
Salary est le nom de la colonne

Autres exemples :

Texte
Salary est compris entre 35000 inclus et 70000 exclus
Salary ge 35000 Salary ID lt 70000

Salary est supérieur à 80000 ou est vide
Salary gt 80000 or Salary eq null

Salary est un nombre à virgule
substringof('.',Salary)

✅ Nombre

eqNombre eq 60000Nombre est = 60000
neNombre ne 45000Nombre est différent de 45000
gtNombre gt 50000Nombre est > 50000
ltNombre lt 90000Nombre est < 90000
geNombre ge 45000Nombre est >= 45000
leNombre le 70000Nombre est <= 70000
startswithstartswith(Nombre,'100')Non pris en charge, retourne une table vide, sans message d'erreur
substringofsubstringof('100',Nombre)Non pris en charge, retourne une table vide, sans message d'erreur
nullNombre ne nullNombre n'est pas vide
Nombre est le nom de la colonne

❌ Nombre calculé

Les filtres OData ne sont pas pris en charge sur les colonnes calculées

🔤 Colonnes texte

✅ Une seule ligne de texte

eqTitle eq 'Item 4534'Title est = 'Item 4534'
neTitle ne 'Item 6547'Title est différent de 'Item 6547'
gtTitle gt 'bonbon'Title est après 'bonbon' dans l'ordre alphabétique
ltTitle lt 'bonbon'Title est avant 'bonbon' dans l'ordre alphabétique
geTitle ge 'bonbon'Title est après 'bonbon' dans l'ordre alphabétique ou Titre = 'bonbon'
leTitle le 'bonbon'Title est avant 'bonbon' dans l'ordre alphabétique ou Titre = 'bonbon'
startswithstartswith(Title ,'bonbon')Title commence par 'bonbon' (Bonbon à la menthe, bonbons à la cerise.))
substringofsubstringof('bonbon',Title )Title contient 'bonbon' (Bonbon à la menthe, Glace parfum bonbon)
nullTitle ne nullTitle n'est pas vide

Autres exemples :

Texte
Title commence par 'Bonbon' et contient "Cerise"
startswith(Title,'bonbon') and substringof('cerise',Title)

Title commence par une lettre entre "B" et "M" inclus ou Title commence par "000"
(Title ge 'b' and Title lt 'n') or Startswith(Title,'000') 

❌ Plusieurs lignes de texte

Les filtres OData ne sont pas pris en charge sur les colonnes de type “plusieurs lignes de texte”

❌ Lien hypertexte

Les filtres OData ne sont pas pris en charge sur les colonnes de type “Lien hypertexte”

🗓️ Colonnes Date / heure

💡 Les colonnes Date et heure peuvent être comparées à un TimeStamp mais ce TimeStamp n’a pas à avoir toutes les composantes : Année, mois, jour, heure, minute, seconde, timezone il est tout à fait possible de n’inclure que l’année et le mois : ‘2025-01’ sera alors interprété comme le 1er janvier 2025 à 00h00 Universal time zone.

✅ Colonne Date

eqDateOfBirth eq '2004-01-01'DateOfBirth est le 1er janvier 2004
neNoDateOfBirth ne '2004-01-01'DateOfBirth est différent de 1er janvier 2024
gtDateOfBirth gt '2004-01'DateOfBirth est après le 31 janvier 2024
ltDateOfBirth lt '2004-01'DateOfBirth est < au 1er janvier 2024
geDateOfBirth ge '2004-01-01'DateOfBirth est >= au 1er janvier 2024
leDateOfBirth le '2004-01-01'DateOfBirth est <= au 1er janvier 2024
startswithstartswith(DateOfBirth ,'2024-01')Non pris en charge, retourne une table vide, sans message d'erreur
substringofsubstringof('24-01',DateOfBirth )Non pris en charge, retourne une table vide, sans message d'erreur
nullDateOfBirth ne nullDateOfBirth n'est pas vide
DateOfBirth est le nom de la colonne
Texte
La DateOfBirth est en 2024
DateOfBirth ge '2024-01' and DateOfBirth lt '2025-01'

La DateOfBirth est entre le 28 juin 2024 et le 31 Mars 2025 inclus
DateOfBirth ge '2024-06-28' and DateOfBirth le '2025-03-31'

✅ Colonne Date et heure

eqCreated eq '2024-03-24T14:52:25Z'L'enregistrement a été créé le 24 mars 2024 à 14h 52min 25sec UTC
neFirstContact ne nullFirstContact n'est pas vide
gtModified gt '2004-01'Les enregistrements modifiés à partir du 1er janvier 2024
ltFirstContact lt '2004-01-01'FirstContact est < au 1er janvier 2024
geFirstContact ge '2004-06-12T12:00'FirstContact est >= au 12 juin 2004 à 12h
leFirstContact le '2004-01-01'FirstContact est <= au 1er janvier 2024
startswithstartswith(FirstContact ,'2024-01')Non pris en charge, retourne une table vide, sans message d'erreur
substringofsubstringof('24-01',FirstContact )Non pris en charge, retourne une table vide, sans message d'erreur

Exemples

Texte
La FirstContact est en 2024
DateOfBirth ge '2024-01-01' and DateOfBirth lt '2025-01-01'

La FirstContact est entre le 28 juin 2024 à 12h et le 31 Mars 2025 inclus
DateOfBirth gt '2024-06-28T12' and DateOfBirth lt '2025-04'

🏷️ Colonnes choix

✅ Colonne Oui / Non

Les colonnes Oui/Non peuvent être comparées aux valeurs : true, false, 1,0, null. Les opérateurs gt, lt, ge et le fonctionnent mais n’ont pas grand intérêt.

eqCheck eq true

Check eq 0
Check vaut "Oui"

Check vaut "Non"
neCheck ne 1

Check ne null
Check ne vaut pas "Oui"

Check n'est pas vide
gtCheck gt falseCheck vaut "Oui"
ltCheck lt 1Check vaut "Non"
geCheck ge 0Check vaut "Oui" ou "Non"
le
Check le true
Check vaut "Oui" ou "Non"

✅ Colonne Choix unique

eqTypeFriandise eq 'Bonbon'TypeFriandise est = 'Bonbon'
neTypeFriandise ne 'Caramel mou'TypeFriandise est différent de 'Caramel mou'
gtTypeFriandise gt 'Nougat'TypeFriandise est après 'Nougat' dans l'ordre alphabétique
ltTypeFriandise lt 'Nougat'TypeFriandise est avant 'Nougat' dans l'ordre alphabétique
geTypeFriandise ge 'Nougat'TypeFriandise est après 'Nougat' dans l'ordre alphabétique ou Statut = 'Nougat'
leTypeFriandise le 'Nougat'TypeFriandise est avant 'Nougat' dans l'ordre alphabétique ou Statut = 'Nougat'
startswithstartswith(TypeFriandise ,'Caramel')TypeFriandise commence par 'Caramel' (Caramel mou, Caramel dur)
substringofsubstringof('Caramel',TypeFriandise )TypeFriandise contient 'Caramel' (Caramel mou, Sucette au caramel)
nullTypeFriandise ne nullTypeFriandise n'est pas vide

Afin d’illustrer pleinement des possibilités de filtrage, nous prendrons comme exemple une colonne de type choix dont les valeurs possibles sont au format [nombre] - [Nom du statut] (il s’agit ici d’une simple concaténation), l’idée est d’avoir des statuts que l’ont pourrait regrouper par étape 0,1,2, 3 etc… La liste des choix ressemblerait à :

  • 0 - Nouveau

  • 0 - Non attribué

  • 1 - En cours d’analyse

  • 1 - En cours de traitement

  • 2 - Approbation demandée

  • 2 - Approbation en cours

  • etc…

Texte
Statut >0 et <4 : tous les statuts de 1 à 3
Statut gt 0 and Statut lt 4

Statut contient "en cours" ou se situe à partir de l'étape 3 mais ne fait pas partie de l'étape 4
(substringof('en cours',Statut) or Statut ge 3) and not(startswith(Statut,'4'))

✅ Colonne Choix Multiple

eqSkills eq 'Power Automate' 'Power Automate' est sélectionné de le champ Skills
neSkills ne 'Power Automate' 'Power Automate' n'est pas sélectionné de le champ Skills
startswithstartswith(Skills ,'Power')Au moins une valeur sélectionnée dans Skills commence par 'Power'
substringofsubstringof('Apps',Skills )Au moins une valeur sélectionnée dans skills contient 'Apps'
nullSkills ne nullSkills n'est pas vide
gt, ge, lt, leNon pris en charge, retourne une table vide, sans message d'erreur
Texte
Skills ne contient pas "Power" et n'est pas vide, sauf si Skills contient un choix commençant par 'Power Apps'
not(substringof('Power',Skills)) and Skills ne null or startswith(Skills,'Power apps')

🎛️ Colonnes complexes

✅ Colonne Recherche

Les requêtes sur les colonnes de type recherche peuvent se faire sur l’ID de l’enregisrement lié ou sur toute autre colonne ajoutée depuis la liste source dans la colonne de type recherche. Les colonnes de la liste source, sont toujours appelées par leur nom de colonne et non par “Value” comme le suggère le JSON de sortie de l’action. Pour cet exemple, nous aurons une colonne ‘LookupField’ qui comporte 3 colonnes de la souce : ‘Title’, ‘Date’ et ‘Amount’

eqLookupField eq 45

LookupField /Title eq 'Parking'
L'ID de LookupField est 45

Le Titre de l'enregistrement lié est 'Parking'
neStaLookupField ne 45L'ID de LookupField est différent de 45
gtLookupField/Amount gt 100Le montant de l'enregistrement lié est strictement supérieur à 100
lt
LookupField /Date lt '2024-03-17'
La date de l'enregistrement lié est antérieure au 17 mars 2024
ge
LookupField/Date ge '2024-03-17'
La date de l'enregistrement lié est à partir du 17 mars 2024
le
LookupField /Amount le 100
Le montant de l'enregistrement lié est inférieur ou égal à 100
startswithstartswith(LookupField /Title,'Park')Le titre de l'enregistrement lié commence par 'Park'
substringofsubstringof('Remboursement',LookupField/Title)Le titre de l'enregistrement lié contient 'Remboursement'
nullLookupField ne null

LookupField/Date eq null
LookupField n'est pas vide

La date de l'engistrement lié est vide
Avec une colonne de recherche nommée"LookupField"

✅ Personne ou groupe

Le champs personne contient un enregistrement, dont les valeurs peuvent être appelées dans le filtrage OData via la syntaxe :

  • NomDeLaColonne/Title: Nom complet / Nom du groupe

  • NomDeLaColonne/EMail (‘E’ et ‘M’ sont bien en majuscules !) : Email de la personne / Email du groupe

eqResponsable/Title eq 'Bob Morane'

Responsable /EMail eq 'robert.marcel@paul.com'
Le nom complet du responsable est 'Bob Morane'

L'email du responsable est 'robert.marcel@paul.com'
neResponsable /EMail ne 'robert.marcel@paul.com'L'email du responsable n'est pas 'robert.marcel@paul.com'
gt
Responsable/Title gt 'david'
Le nom complet est après 'David' dans l'ordre alphabétique
lt
Responsable/Title lt 'z'
Le nom complet est avant 'z' dans l'ordre alphabétique
ge
Responsable/Title 'John Smith'
Le nom complet du responsable est John Smith ou un nom situé après dans l'ordre alphabétique
le
Responsable/EMail ge 'John Smith'
Le nom complet du responsable est John Smith ou un nom situé avant dans l'ordre alphabétique
startswithstartswith(Editor/Title,'svc-')le nom de l'éditeur commence par 'svc-'
substringofsubstringof('-ext@',Author/EMail)l'Email de l'auteur contient '-ext@'
nullResponsable /EMail ne nullResponsable n'est pas vide
Avec une colonne de recherche nommée"Responsable", fonctionne également avec les colonnes natives "Author" (Créé par) et "Editor" (Modifié par)
Texte
Skills ne contient pas "Power" et n'est pas vide, sauf si Skills contient un choix commençant par 'Power Apps'
not(substringof('Power',Skills)) and Skills ne null or startswith(Skills,'Power apps')

🔶 Emplacement

Les filtres OData ne sont pas pris en charge sur les colonnes de type “Emplacement”

Mais… L’ajout d’une colonne emplacement ajoute également des colonnes supplémentaires qui peuvent être filtrées comme des colonnes Texte :

Exemples :

Texte
L'emplacement contient "gare"
substringof('gare',DispName)

Le code postal commence par '440' et le pays est 'France'
startswith(PostalCode,'440') and CountryOrRegion eq 'France'

📁 Filtrage des bibliothèques de documents

Dans un action “obtenir les fichiers” pour un bibliothèque il est également possible d’utiliser un filtre OData sur les propriétés des fichiers. La plus grand difficulté réside dans le fait que les noms des colonnes utilisés dans les requêtes est différent des noms dans le JSON de sortie de l’action.

Nom du fichier avec extension: FileLeafRef

Est une colonne de type texte

Texte
Commence par Rapport :
startswith(FileLeafRef,'Rapport')
Contient Facture :
substringof('Facture', FileLeafRef)

Est un dossier : FSObjType

Est une colonne de type booléen (Oui / Non)

Texte
Dossiers uniquement :
FSObjType eq 1
Fichiers uniquement :
FSObjType eq 0

Extension du fichier : File_x0020_Type

Est une colonne de type texte

Texte
Fichiers word uniquement :
File_x0020_Type eq 'docx'
Fichiers Excel uniquement, xls ou xlsx :
startswith(File_x0020_Type ,'xls')

URL Relative: FileRef

Est une colonne de type texte

Chemin d’accès au dossier : FileDirRef

Est une colonne de type texte

Texte
Est dans un dossier spécifique :
FileRef eq 'Documents partages/_Template_Dossier_Client/'

Est dans un dossier ou un de ses sous-dossier :
startswith(FileRef,'Documents partages/_Template_Dossier_Client/')

Échanger autour de cet article

Les commentaires utilisent Giscus et GitHub Discussions. Le service externe n’est contacté qu’après activation.