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.

- Le protocole OData avec Power Automate
- Les fonctions & opérateurs
- Possibilités de filtrage par type de colonne SharePoint
- 📁 Filtrage des bibliothèques de documents
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.
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.
</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é
Titre eq 'abcdef'
Champ numérique eq 123.45
ne (not equal)
Permet d’évaluer une différence
Titre ne 'abcdef'
Champ numérique ne 123.45
not
Inverse le résultat de l’évaluation contenue entre ()
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
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)
ChampDecimal lt 123.45
ChampDate lt '2025-01-01'
ge (greater or equal)
Retourne les valeurs supérieures ou égales
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)
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.
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.
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 :
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 :
Titre eq 'abcdef' or Num eq 123.45 and ChampDate gt 2025-01-01
Équivaut à :
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’ )
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 )
substringof( 'abcd' ,Titre )
Remontera les lignes dont le titre contient “abcd”
Possibilités de filtrage par type de colonne SharePoint
🔢 Colonnes numériques
✅ ID
| eq | ID eq 123 | L'ID est 123 |
| ne | ID ne 12 | L'ID est diffèrent de 12 |
| gt | ID gt 10 | l'ID est > 10 |
| lt | ID lt 99 | l'ID est < 99 |
| ge | ID ge 15 | l'ID est >= 15 |
| le | ID le 60 | l'ID est <= 60 |
| startswith | startswith(ID,'10') | l'ID commence par '10' ( 10, 103, 1025...)) |
| substringof | substringof('10',ID) | l'ID contient '10' (10, 210, 4106...) |
Autres exemples :
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
| eq | Salary eq 60000 | Salary est = 60000 |
| ne | Salary ne 80000 | Salary est différent de 80000 |
| gt | Salary gt 50000 | Salary est > 50000 |
| lt | Salary lt 90000 | Salary est < 90000 |
| ge | Salary ge 45000 | Salary est >= 45000 |
| le | Salary le 70000 | Salary est <= 70000 |
| startswith | startswith(Salary ,'100') | Salary commence par '10' ( 1000, 100500, 10200...)) |
| substringof | substringof('100',Salary ) | Salary contient '100' (110000, 45100, 81005..) |
| null | Salary ne null | Salary n'est pas vide |
Autres exemples :
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
| eq | Nombre eq 60000 | Nombre est = 60000 |
| ne | Nombre ne 45000 | Nombre est différent de 45000 |
| gt | Nombre gt 50000 | Nombre est > 50000 |
| lt | Nombre lt 90000 | Nombre est < 90000 |
| ge | Nombre ge 45000 | Nombre est >= 45000 |
| le | Nombre le 70000 | Nombre est <= 70000 |
| startswith | startswith(Nombre,'100') | Non pris en charge, retourne une table vide, sans message d'erreur |
| substringof | substringof('100',Nombre) | Non pris en charge, retourne une table vide, sans message d'erreur |
| null | Nombre ne null | Nombre n'est pas vide |
❌ Nombre calculé
Les filtres OData ne sont pas pris en charge sur les colonnes calculées

🔤 Colonnes texte
✅ Une seule ligne de texte
| eq | Title eq 'Item 4534' | Title est = 'Item 4534' |
| ne | Title ne 'Item 6547' | Title est différent de 'Item 6547' |
| gt | Title gt 'bonbon' | Title est après 'bonbon' dans l'ordre alphabétique |
| lt | Title lt 'bonbon' | Title est avant 'bonbon' dans l'ordre alphabétique |
| ge | Title ge 'bonbon' | Title est après 'bonbon' dans l'ordre alphabétique ou Titre = 'bonbon' |
| le | Title le 'bonbon' | Title est avant 'bonbon' dans l'ordre alphabétique ou Titre = 'bonbon' |
| startswith | startswith(Title ,'bonbon') | Title commence par 'bonbon' (Bonbon à la menthe, bonbons à la cerise.)) |
| substringof | substringof('bonbon',Title ) | Title contient 'bonbon' (Bonbon à la menthe, Glace parfum bonbon) |
| null | Title ne null | Title n'est pas vide |
Autres exemples :
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
| eq | DateOfBirth eq '2004-01-01' | DateOfBirth est le 1er janvier 2004 |
| ne | NoDateOfBirth ne '2004-01-01' | DateOfBirth est différent de 1er janvier 2024 |
| gt | DateOfBirth gt '2004-01' | DateOfBirth est après le 31 janvier 2024 |
| lt | DateOfBirth lt '2004-01' | DateOfBirth est < au 1er janvier 2024 |
| ge | DateOfBirth ge '2004-01-01' | DateOfBirth est >= au 1er janvier 2024 |
| le | DateOfBirth le '2004-01-01' | DateOfBirth est <= au 1er janvier 2024 |
| startswith | startswith(DateOfBirth ,'2024-01') | Non pris en charge, retourne une table vide, sans message d'erreur |
| substringof | substringof('24-01',DateOfBirth ) | Non pris en charge, retourne une table vide, sans message d'erreur |
| null | DateOfBirth ne null | DateOfBirth n'est pas vide |
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
| eq | Created eq '2024-03-24T14:52:25Z' | L'enregistrement a été créé le 24 mars 2024 à 14h 52min 25sec UTC |
| ne | FirstContact ne null | FirstContact n'est pas vide |
| gt | Modified gt '2004-01' | Les enregistrements modifiés à partir du 1er janvier 2024 |
| lt | FirstContact lt '2004-01-01' | FirstContact est < au 1er janvier 2024 |
| ge | FirstContact ge '2004-06-12T12:00' | FirstContact est >= au 12 juin 2004 à 12h |
| le | FirstContact le '2004-01-01' | FirstContact est <= au 1er janvier 2024 |
| startswith | startswith(FirstContact ,'2024-01') | Non pris en charge, retourne une table vide, sans message d'erreur |
| substringof | substringof('24-01',FirstContact ) | Non pris en charge, retourne une table vide, sans message d'erreur |
Exemples
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.
| eq | Check eq true Check eq 0 | Check vaut "Oui" Check vaut "Non" |
| ne | Check ne 1 Check ne null | Check ne vaut pas "Oui" Check n'est pas vide |
| gt | Check gt false | Check vaut "Oui" |
| lt | Check lt 1 | Check vaut "Non" |
| ge | Check ge 0 | Check vaut "Oui" ou "Non" |
| le | Check le true | Check vaut "Oui" ou "Non" |
✅ Colonne Choix unique
| eq | TypeFriandise eq 'Bonbon' | TypeFriandise est = 'Bonbon' |
| ne | TypeFriandise ne 'Caramel mou' | TypeFriandise est différent de 'Caramel mou' |
| gt | TypeFriandise gt 'Nougat' | TypeFriandise est après 'Nougat' dans l'ordre alphabétique |
| lt | TypeFriandise lt 'Nougat' | TypeFriandise est avant 'Nougat' dans l'ordre alphabétique |
| ge | TypeFriandise ge 'Nougat' | TypeFriandise est après 'Nougat' dans l'ordre alphabétique ou Statut = 'Nougat' |
| le | TypeFriandise le 'Nougat' | TypeFriandise est avant 'Nougat' dans l'ordre alphabétique ou Statut = 'Nougat' |
| startswith | startswith(TypeFriandise ,'Caramel') | TypeFriandise commence par 'Caramel' (Caramel mou, Caramel dur) |
| substringof | substringof('Caramel',TypeFriandise ) | TypeFriandise contient 'Caramel' (Caramel mou, Sucette au caramel) |
| null | TypeFriandise ne null | TypeFriandise 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…
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
| eq | Skills eq 'Power Automate' | 'Power Automate' est sélectionné de le champ Skills |
| ne | Skills ne 'Power Automate' | 'Power Automate' n'est pas sélectionné de le champ Skills |
| startswith | startswith(Skills ,'Power') | Au moins une valeur sélectionnée dans Skills commence par 'Power' |
| substringof | substringof('Apps',Skills ) | Au moins une valeur sélectionnée dans skills contient 'Apps' |
| null | Skills ne null | Skills n'est pas vide |
| gt, ge, lt, le | Non pris en charge, retourne une table vide, sans message d'erreur |
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’

| eq | LookupField eq 45 LookupField /Title eq 'Parking' | L'ID de LookupField est 45 Le Titre de l'enregistrement lié est 'Parking' |
| ne | StaLookupField ne 45 | L'ID de LookupField est différent de 45 |
| gt | LookupField/Amount gt 100 | Le 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 |
| startswith | startswith(LookupField /Title,'Park') | Le titre de l'enregistrement lié commence par 'Park' |
| substringof | substringof('Remboursement',LookupField/Title) | Le titre de l'enregistrement lié contient 'Remboursement' |
| null | LookupField ne null LookupField/Date eq null | LookupField n'est pas vide La date de l'engistrement lié est vide |
✅ 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
| eq | Responsable/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' |
| ne | Responsable /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 |
| startswith | startswith(Editor/Title,'svc-') | le nom de l'éditeur commence par 'svc-' |
| substringof | substringof('-ext@',Author/EMail) | l'Email de l'auteur contient '-ext@' |
| null | Responsable /EMail ne null | Responsable n'est pas vide |
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 :
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
Commence par Rapport :
startswith(FileLeafRef,'Rapport')
Contient Facture :
substringof('Facture', FileLeafRef)
Est un dossier : FSObjType
Est une colonne de type booléen (Oui / Non)
Dossiers uniquement :
FSObjType eq 1
Fichiers uniquement :
FSObjType eq 0
Extension du fichier : File_x0020_Type
Est une colonne de type 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
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.