1+ import logging
2+
3+ from c8y_api .app import SimpleCumulocityApp
4+ from c8y_api .model import Device
5+ from c8y_api .model .matcher import field
6+ from util .testing_util import load_dotenv
7+
8+ logging .basicConfig (level = logging .DEBUG )
9+
10+ """
11+ This example demonstrates how to use the client-side-filtering feature of the
12+ Python Cumulocity API.
13+
14+ Client-side filtering is _not_ part of the standard API, it is an extension
15+ which the Python API provides which _can_ be useful in _some_ use cases. It
16+ is important to understand, that client-side-filtering is somewhat a tool of
17+ last resort - it becomes necessary if server-side filtering is not sufficient.
18+ Python being Python already provides nice standard features for filtering the
19+ query results, e.g. via list comprehension or the `filter` function. However,
20+ sometimes it may appear easier for developers to define such a filter directly
21+ with the `select` or `get_all` function, for example in interactive scenarios.
22+
23+ Client-side filters are defined for the _raw_ JSON structure. Hence, when you
24+ want to use them you must be aware of Cumulocity's JSON data format.
25+
26+ Performance: Hi there, optimization kids! To put it bluntly - using this
27+ feature does most likely _not_ increase performance in any way. This is
28+ because the actual JSON parsing will happen in any case and this is the
29+ expensive part. So - all the illustrated methods below do only marginally
30+ differ in speeed.
31+ """
32+
33+ load_dotenv () # load environment from a .env if present
34+ c8y = SimpleCumulocityApp ()
35+ print ("CumulocityApp initialized." )
36+ print (f"{ c8y .base_url } , Tenant: { c8y .tenant_id } , User:{ c8y .username } " )
37+
38+ # Let's create a couple of devices with arbitrary names
39+ d1 = Device (c8y = c8y , type = "c8y_TestDevice" , name = "Some Test Device" ).create ()
40+ d2 = Device (c8y = c8y , type = "c8y_TestDevice" , name = "Device #2" ).create ()
41+ d3 = Device (c8y = c8y , type = "c8y_TestDevice" , name = "Another Device" ).create ()
42+ d4 = Device (c8y = c8y , type = "c8y_TestDevice" , name = "Machine thingy" ).create ()
43+
44+ print ("All devices of type 'c8y_TestDevice':" )
45+ for d in c8y .device_inventory .select (type = 'c8y_TestDevice' ):
46+ print (f" - { d .name } " )
47+
48+ # Option 1: filtering devices by name using Python filters
49+ # The following select statement will simply list "all" devices (there are
50+ # no DB filters) and subsequently filter the results using a standard Python
51+ # list comprehension:
52+ filtered_devices = [x for x in c8y .device_inventory .select (type = 'c8y_TestDevice' ) if 'Device' in x .name ]
53+ # -> We will only have devices which are named "Device something"
54+ print ("Option #1 result (needs to contain 'Device' string)" )
55+ for d in filtered_devices :
56+ print (f" - { d .name } " )
57+
58+ # Option 2: using the client-side filtering with JMESPath filters
59+ # The following statement will simply list "all" devices (there are no DB
60+ # filters) and subsequently filter the results using a JMESPath expression.
61+ # The JMESPath is matched against the unprocessed JSON, hence it is required
62+ # to understand Cumulocity's native JSON formats (but they are close to how
63+ # the Python API resembles it:
64+ filtered_devices_2 = c8y .device_inventory .get_all (type = 'c8y_TestDevice' , include = "contains(name, 'Device')" )
65+ # -> We will only have devices which are named "Device something"
66+ print ("Option #2 result (same thing):" )
67+ for d in filtered_devices_2 :
68+ print (f" - { d .name } " )
69+
70+ # Option 3: the client-side filtering with Python filters
71+ # The following statement will simply list "all" devices (there are no DB
72+ # filters) and subsequently filter the results using Python matchers. There
73+ # is quite a list of predefined matchers (see c8y_api.model.matchers) and
74+ # custom ones are easy to define.
75+ filtered_devices_3 = c8y .device_inventory .get_all (
76+ type = 'c8y_TestDevice' ,
77+ include = field ('name' , '*Device*' ),
78+ exclude = field ('name' , '*#*' ))
79+ # -> We will only have devices which are named "Device something" but
80+ # without '#' anywhere in the name
81+ print ("Option #3 result (Same, but no #)" )
82+ for d in filtered_devices_3 :
83+ print (f" - { d .name } " )
84+
85+
86+ # cleanup
87+ d1 .delete ()
88+ d2 .delete ()
89+ d3 .delete ()
90+ d4 .delete ()
0 commit comments