Couchbase-lite-2.0 IOS - Querying is not generic anymore.

query

#1

Hi,

Couchbase 1.4.x querying is very generic when compared to 2.x,

1.4.x query builder,

let predicate = NSPredicate(format: "createdby == 'user1' AND (ANY detail.jobcode IN {'Jobcode1', 'Jobcode2’}")
let results = try? CBLQueryBuilder(database: self.database, select:[], wherePredicate: predicate, orderBy: nil).runQuery(withContext: nil)

But, In 2.x it’s different,

let DETAILS = ArrayExpression.variable("DETAILS") 
let DETAILS_JOBCODES = ArrayExpression.variable("DETAILS.jobcode") 
let a = [Expression.string("Jobcode1"), Expression.string("Jobcode2")]
let query = QueryBuilder 
.select(SelectResult.all()) 
.from(DataSource.database(database!)) 
.where(ArrayExpression.any(DETAILS).in(Expression.property("details")).satisfies(Expression.not(DETAILS_JOBCODES.in(a))))

Because, we are using a generic code base for more than 100 queries. So, we are facing a hard time converting the above string’s to expression’s to work with the latest couchbase-lite-2.0 app.

In 1.4.x, I can change this string "createdby == 'user1' AND (ANY detail.jobcode IN {'Jobcode1', 'Jobcode2’}" dymanically from the document and use it in queries. But, we can’t do this in 2.x.


#2

Could you explain the goal a little more clearly? Sure you can change the string dynamically in 1.4.x but I still think that means you have a different query each time. What do you mean by “change the string dynamically” and how do you want to apply that to 2.x?


#3

It’s a more strongly-typed API, yes. This is to reduce the likelihood of creating invalid queries.

You can still construct queries dynamically; you’re just doing it by dynamically connecting together the objects in the builder API, instead of dynamically concatenating strings.


#4

@borrrden We have published only one app in AppStore. So, all the client’s will use the same app, but for each client we have different operation tools in it.

For client1, our queries will be from a Couchbase document like the below,

let selectedToolQueryKey =  "jobtool.jobcode1" --> This will come from what we are selecting.
guard let queryDocument  =  database.document(withID: "genericquerystorageforclient1") ,
               let queryDictionary  =  queryDocument.properties,
               let queryString  = queryDictionary[selectedToolQueryKey] as?  String, 
else { return }

let predicate = NSPredicate(format: queryString)
let results = try? CBLQueryBuilder(database: self.database, select:[], wherePredicate: predicate, orderBy: nil).runQuery(withContext: nil)

My query document,

 {
      "_id": "genericquerystorageforclient1",
      "syncchannel": "client1channel",
      "syncuser": "client1user",
      "queries": {
        "jobtool": {
          "jobcode1": "createdby == 'appuser' AND detail.jobcode = 'jobcode1'",
          "jobcode2": "createdby == 'appuser' AND detail.jobcode = 'jobcode2'",
          "jobcode3": "createdby == 'appuser' AND detail.jobcode = 'jobcode3'",
          "default": "createdby == 'appuser' AND detail.jobcode != ''",
          "hoursdashboardtool": {
            "dashboardblock1": "createdby == 'appuser' AND totalworkedhours >= '8.00'",
            "dashboardblock2": "createdby == 'appuser' AND totalworkedhours < '8.00'",
            "dashboardblock3": "createdby == 'appuser' AND detail.@sum.workedhours"
          },
          "prioritydashboardtool": {
            "priority1": "jobstatus == 'notcompleted' AND jobpriority = 'High'",
            "priority2": "jobstatus == 'notcompleted' AND jobpriority = 'Medium'",
            "priority3": "jobstatus == 'notcompleted' AND jobpriority = 'Low'"
          }
        }
      }
    }

Like the above we have different queries for each of the client. Also, I have added only one tool, but we have more than 30 tool like this in our apps. I can’t post everything here.

Even, I can make more complex queries,

NSPredicate(format: "createdby == 'user1' AND (ANY detail.jobcode IN {'Sick', 'Vacation’})")
NSPredicate(format: "createdby == 'user1' AND NOT (ANY detail.jobcode IN {'Sick', 'Vacation’})")

#5

@jens Yeah, We can construct the queries dynamically in couchbase2.x. But, it not that easy, Please take a look at the above reply and let me know How to construct that dynamically in 2.x?


#6

We do actually use an internal string-based (JSON) syntax for queries, but it’s not exposed in the API.

There’s also an unused piece of code that translates an NSPredicate to this syntax.

Paging our PM @priya.rajagopal — here’s a use case for exposing JSON queries.