Aller au contenu principal

Rechercher des données

Ce guide explique comment récupérer le bon type de données selon votre usage, en utilisant l'API de recherche de Stonal avec des filtres, de la pagination et des schémas de recherche avancés.

info

Vous devrez obtenir un jeton d'accès personnel pour utiliser l'API de recherche.

Démarrage

Authentification

Voici un exemple de requête autour de l'API de recherche, où nous allons récupérer des BUILDING_GROUP et des BUILDING.

Vous devez passer une requête ressemblant à ceci :

📄 search.sh
#!/bin/sh -ex

# Your organization
STONAL_ORG=DEMO

# Fetch your token from here: https://app.stonal.io/users/app
STONAL_TOKEN=9631e269-e21e-4ce6-92a9-c6f7ed1fa98a

curl \
https://api.stonal.io/datalake/v1/organizations/$STONAL_ORG/assets/search \
-v \
-X POST \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $STONAL_TOKEN" \
-d @query.json -o output.json

Requête initiale

📄 query.json
{
"search": {
"type": {
"equals": [
"BUILDING",
"BUILDING_GROUP"
]
}
},
"properties": {
"simple": ["LAT", "LNG"]
},
"fields": [
"name",
"type",
"uid",
"externalIds"
],
"paginate": {
"size": 2
}
}

La sortie sera semblable à ceci :

📄 output.json
{
"assets": [
{
"uid": "f6472f1a-9473-4fbf-9e1c-1c063eebb430",
"name": "Building Group 1",
"type": "BUILDING_GROUP",
"externalIds": {
"SOURCE_NAME": "BG001"
},
"properties": {
"simple": {
"LAT": "46.800",
"LNG": "1.6959"
}
}
},
{
"uid": "b81ce341-86f0-4cfe-a806-1d4a0f9a12ed",
"name": "Building 1",
"type": "BUILDING",
"externalIds": {
"SOURCE_NAME": "B001"
},
"properties": {
"simple": {
"LAT": "46.500",
"LNG": "1.7959"
}
}
}
],
"paginate": {
"size": 2,
"cursor": "123456"
}
}

Requêtes suivantes

Ensuite, pour récupérer le lot suivant de 10 objets, vous devez émettre la même requête avec le paginate.cursor défini à la valeur reçue, c.-à-d. "123456".

📄 query.json
{
"search": {
"type": {
"equals": [
"BUILDING",
"BUILDING_GROUP"
]
}
},
"fields": [
"name",
"type",
"uid",
"externalIds",
"parent"
],
"paginate": {
"size": 2,
"cursor": "123456"
}
}

La sortie sera semblable à ceci :

📄 output.json
{
"assets": [
{
"uid": "dd127caf-5b9b-4116-884e-b42505ac1bd6",
"name": "Building Group 2",
"type": "BUILDING_GROUP",
"externalIds": {
"CODE": "BG002"
}
},
{
"uid": "2c2ca7be-78f1-4734-a4c6-bbc773c9027b",
"name": "Building 2",
"type": "BUILDING",
"externalIds": {
"CODE": "B002"
},
"parent": {
"uid": "dd127caf-5b9b-4116-884e-b42505ac1bd6"
}
}
],
"paginate": {
"size": 2,
"cursor": "234567"
}
}

Pour aller plus loin

Il existe de nombreuses autres façons d'interroger les données. Et vous pouvez combiner n'importe lequel de ces filtres.

Rechercher par identifiants externes

Vous pouvez effectuer une recherche à l'aide d'un seul identifiant externe, soit issu de l'objet lui-même, soit de ses relations.

Rechercher un objet précis par l'un de ses identifiants externes.

🔎 by asset's external ID
"search": {
"asset": {
"externalIds": {
"SOURCE_NAME": "BG001"
}
}
}

Rechercher les objets dont le parent correspond à l'identifiant externe donné.

🔎 by the external ID of asset’s parent
"search": {
"parent": {
"externalIds": {
"SOURCE_NAME": "BG001"
}
}
}

Les objets sont organisés selon une hiérarchie (voir Hiérarchie des objets). Vous pouvez utiliser les filtres de relation suivants pour naviguer vers le haut et vers le bas de l'arborescence. Un seul filtre de relation peut être utilisé par requête.

Trouver les enfants directs d'un parent

Utilisez parent pour trouver tous les objets qui sont des enfants directs d'un objet parent donné.

🔎 direct children of a building group
"search": {
"parent": { "uid": "dd127caf-5b9b-4116-884e-b42505ac1bd6" }
}

Trouver tous les descendants d'un ancêtre

Utilisez parentRecursive pour trouver tous les objets imbriqués sous un ancêtre donné, à n'importe quelle profondeur.

🔎 all descendants of a building group (buildings, plans, levels, spaces, equipments...)
"search": {
"parentRecursive": { "externalIds": { "CODE": "SITE_001" } }
}

Trouver les parents directs d'un enfant

Utilisez child pour trouver les objets qui sont des parents directs d'un objet enfant donné.

🔎 direct parents of a building
"search": {
"child": { "uid": "b81ce341-86f0-4cfe-a806-1d4a0f9a12ed" }
}

Trouver tous les ancêtres d'un descendant

Utilisez childRecursive pour trouver tous les objets ancêtres d'un descendant donné, à n'importe quelle profondeur. C'est utile pour remonter la hiérarchie depuis un objet feuille (par exemple un équipement) afin de trouver son bâtiment, son groupe de bâtiments, etc.

🔎 find the building of an equipment
{
"search": {
"childRecursive": { "uid": "$equipmentUid" },
"type": { "equals": ["BUILDING", "BUILDING_SECTION"] }
},
"fields": ["name", "type"],
"paginate": { "size": 10 }
}

Vous pouvez aussi utiliser externalIds pour identifier le descendant :

🔎 find all ancestors of an equipment by external ID
"search": {
"childRecursive": {
"externalIds": { "TRIRIGA": "EQP1008473" }
}
}
remarque

childRecursive renvoie tous les ancêtres mais exclut des résultats l'objet enfant interrogé lui-même. Tous les autres filtres (type, name, fields, properties, paginate) s'appliquent normalement aux ancêtres renvoyés.

Correspondance sur un motif

Vous pouvez rechercher des types correspondant à un motif d'expression régulière.

Rechercher des espaces

remarque

SPACE est un autre nom pour les pièces dans la plateforme Stonal.

Ceci renverra des objets de types SPACE et SPACE|* :

🔎 asset type pattern
"search": {
"type": {
"matches": [
"SPACE",
"SPACE\\|.*"
]
}
}

Veuillez noter que ceci s'appliquera à tous les espaces de l'organisation. Si vous souhaitez le limiter à un bâtiment particulier, vous devriez le combiner avec un filtre parent comme ceci :

🔎 spaces within a specific building group
"search": {
"type": {
"matches": [
"SPACE",
"SPACE\\|.*"
]
},
"parent": {
"externalIds": {
"SOURCE_NAME": "BG001"
}
}
}

Exclure par type

info

Un seul de notMatches ou notEquals est accepté (de même que matches et equals)

Par correspondance sur un motif

Exclure des équipements spécifiés (ceux ayant un type commençant par EQUIPMENT|C|CA|) lors du listage des équipements d'un groupe de bâtiments

Using Regex to exclude types
"search": {
"type": {
"matches": ["EQUIPMENT\\|.*"],
"notMatches": ["EQUIPMENT\\|C\\|CA\\|.*"]
},
"parentRecursive": {
"externalIds": { "CODE": "SITE_001" }
}
}

Par égalité stricte

Exclure des équipements spécifiés (ceux ayant un type égal à EQUIPMENT|C|CA|CA01 ou EQUIPMENT|A|AA) lors du listage des équipements d'un groupe de bâtiments

Using strict equality to exclude types
"search": {
"type": {
"matches": ["EQUIPMENT\\|.*"],
"notEquals": ["EQUIPMENT|C|CA|CA01", "EQUIPMENT|A|AA"]
},
"parentRecursive": {
"externalIds": { "CODE": "SITE_001" }
}
}

Filtrer sur la donnée courante d'une propriété

Les objets portent des propriétés : des points de données comme l'adresse, la surface locative, la date de construction ou le nombre de locataires. Chaque propriété est identifiée par un code (par ex. ADDRESS, RENTAL_AREA, BUILDING_DATE, TENANT_COUNT).

info

Les codes de propriété pour chaque type d'objet sont listés dans le produit DQC. Voir Récupérer un sous-ensemble de propriétés pour plus de détails.

Ajoutez un bloc search.properties pour filtrer les objets selon les valeurs de leurs propriétés.

astuce

search.properties filtre quels objets sont renvoyés. Le properties de niveau racine contrôle quelles données apparaissent dans la réponse. Ils peuvent être utilisés ensemble.

Exemple : bâtiments du 8e arrondissement de Paris ayant plus de 2 locataires

{
"search": {
"properties": {
"conditions": [
{ "op": "gt", "property": "TENANT_COUNT", "value": "2" },
{ "op": "contains", "property": "ADDRESS", "value": "75008 Paris" }
]
},
"type": {
"equals": ["BUILDING"]
}
},
"fields": ["uid", "name", "type"],
"properties": {
"simple": ["TENANT_COUNT", "ADDRESS"]
},
"paginate": { "size": 50 }
}

Structure d'une condition

Une condition est un objet comportant les champs suivants :

ChampDescription
opL'opérateur à appliquer (voir Opérateurs ci-dessous)
propertyLe code de propriété sur lequel filtrer (pour les conditions feuilles)
valueLa valeur à comparer (pour les opérateurs à valeur unique)
valuesUne liste de valeurs à comparer (pour les opérateurs in/notIn)
conditionsUne liste de conditions imbriquées (pour les opérateurs de groupe and/or)

Plusieurs conditions au niveau racine sont combinées avec un ET. Utilisez des groupes or/and pour une logique explicite :

🔎 address contains 75008 Paris OR more than 10 tenants
{ "op": "or", "conditions": [
{ "op": "contains", "property": "ADDRESS", "value": "75008 Paris" },
{ "op": "gt", "property": "TENANT_COUNT", "value": "10" }
]}

Les groupes peuvent être imbriqués :

🔎 main property type is Bureau AND (rental area > 500 OR more than 10 tenants)
{
"conditions": [
{ "op": "eq", "property": "MAIN_ASSET_NATURE", "value": "Bureau" },
{ "op": "or", "conditions": [
{ "op": "gt", "property": "RENTAL_AREA", "value": "500" },
{ "op": "gt", "property": "TENANT_COUNT", "value": "10" }
]}
]
}

Opérateurs

Comparaison

Les comparaisons de texte sont insensibles à la casse et aux accents (« chatelet » correspond à « Châtelet »).

OpérateurDescriptionChamps requis
eqÉgalvalue
neqDifférentvalue
inCorrespond à une valeur quelconque d'une listevalues (non vide)
notInNe correspond à aucune des valeursvalues (non vide)
🔎 main property type is Bureau
{ "op": "eq", "property": "MAIN_ASSET_NATURE", "value": "Bureau" }
🔎 main property type is Commerce or Logement
{ "op": "in", "property": "MAIN_ASSET_NATURE", "values": ["Commerce", "Logement"] }
Texte
OpérateurDescriptionChamps requis
containsCorrespondance de sous-chaîne (insensible à la casse/aux accents)value
notContainsExclut la correspondance de sous-chaînevalue
regexCorrespondance par expression régulièrevalue (regex valide)
notRegexExclut la correspondance par regexvalue (regex valide)
🔎 address contains 'Rue du chat'
{ "op": "contains", "property": "ADDRESS", "value": "Rue du chat" }
Numérique et date

Toutes les valeurs sont passées sous forme de chaînes mais doivent être un nombre valide (par ex. "100") ou une date ISO 8601 (par ex. "2024-01-15").

OpérateurDescriptionChamps requis
gtStrictement supérieur àvalue (nombre ou date)
gteSupérieur ou égal àvalue (nombre ou date)
ltStrictement inférieur àvalue (nombre ou date)
lteInférieur ou égal àvalue (nombre ou date)
🔎 rental area between 100 and 500
{
"conditions": [
{ "op": "gte", "property": "RENTAL_AREA", "value": "100" },
{ "op": "lte", "property": "RENTAL_AREA", "value": "500" }
]
}
🔎 buildings constructed after 2000
{ "op": "gt", "property": "BUILDING_DATE", "value": "2000-01-01" }
Présence
OpérateurDescriptionChamps requis
isNullAucune valeur courante pour cette propriétéaucun (value/values doivent être absents)
isNotNullA une valeur couranteaucun (value/values doivent être absents)
🔎 assets with no address
{ "op": "isNull", "property": "ADDRESS" }
Groupes logiques
OpérateurDescriptionChamps requis
andToutes les conditions imbriquées doivent correspondreconditions (au moins 2)
orAu moins une doit correspondreconditions (au moins 2)

Négation et données manquantes

Les opérateurs de négation (neq, notIn, notContains, notRegex) excluent les objets qui n'ont aucune valeur pour la propriété. Pour les inclure, combinez avec isNull :

🔎 main property type is not Commerce or Parking, including assets without one
{ "op": "or", "conditions": [
{ "op": "notIn", "property": "MAIN_ASSET_NATURE", "values": ["Commerce", "Parking"] },
{ "op": "isNull", "property": "MAIN_ASSET_NATURE" }
]}

Récupérer un sous-ensemble de champs

Les champs sont des attributs directement associés à un objet. Vous pouvez spécifier quels champs récupérer.

Valeurs autorisées : uid, name, updatedAt, deletedAt, type, externalIds, representations, parent

L'identifiant unique uid est toujours renvoyé.

🔎 get asset's name, date of update and external ids
{
"search": {
"asset": { "uid": "2cb3683a-90f6-48de-aaa0-08f45c7bf808" }
},
"fields": ["name", "updatedAt", "externalIds"]
}

Récupérer un sous-ensemble de propriétés

Les propriétés sont associées à des données chronologiques liées à un objet.

Vous pouvez récupérer la donnée de référence d'une propriété spécifiée à l'instant courant.

info

Les éléments de la liste simple font référence au code de la propriété.

Ce code peut être trouvé dans notre produit DQC pour chaque type d'objet

Dans cet exemple, nous sommes sur un BUILDING, sa propriété nommée Adresse a ADDRESS pour code.

Capture d'écran depuis DQC sur une URL du type https://app.stonal.io/dqc/$ORGANIZATION_CODE/asset-types/EQUIPMENT/assets/$ASSET_UID dqc_building_properties.png

Nb : le code peut aussi avoir un format uuid

Dans cet exemple, nous sommes sur un EQUIPMENT, sa propriété nommée Date dernier renouvellement a 43f1f705-b3b3-4ff3-9ca3-a5c5ed638eef pour code.

Capture d'écran depuis DQC sur une URL du type https://app.stonal.io/dqc/$ORGANIZATION_CODE/asset-types/EQUIPMENT/assets/$ASSET_UID

dqc_equipment_properties.png

🔎 get building's data for ADDRESS and BUILDING_DATE property
{
"search": {
"type": { "equals": ["BUILDING"] }
},
"properties": {
"simple": ["ADDRESS", "BUILDING_DATE"]
}
}
➡️ response with current reference data for ADDRESS and BUILDING_DATE property
{
"assets": [
{
"uid": "1321987a-b94f-4180-ab93-94432be0855f",
"properties": {
"simple": {
"ADDRESS": "28 Cr Albert 1er, 75008 Paris",
"BUILDING_DATE": "2001-09-29"
}
}
}
]
}

Mise à jour différentielle

Vous pouvez rechercher les données qui ont été mises à jour depuis une date particulière.

🔎 differential update
"search": {
"updatedAtAfter": "2025-09-12T00:00:00"
}

Détecter les objets supprimés

Dans la réponse de recherche, vous pouvez aussi inclure les objets supprimés correspondant aux filtres spécifiés.

🔎 detect deleted assets
"search": {
"updatedAtAfter": "2025-09-12T00:00:00",
"includeDeleted": true
}

Photos des objets

Ceci s'applique principalement aux objets BUILDING_GROUP et BUILDING.

Si l'objet possède un PHOTO_ID, nous pouvons y accéder directement en utilisant ce modèle d'URL :

https://api.stonal.io/document-storage/v1/organizations/$org/documents/$photoId/content

Nous fournissons également un redimensionnement et une génération de miniatures pour les photos à l'aide d'imagor afin que vous puissiez l'utiliser directement dans votre API frontend :

https://cdn-api.stonal.io/imagor/unsafe/fit-in/200x/api.stonal.io/document-storage/v1/organizations/$org/documents/$photoId/content
info

Le unsafe dans l'URL signifie que vous n'avez pas besoin de signer l'URL, mais son usage est sûr.