How do I query for nil values with CloudKit.js? - cloudkit

Using CloudKit.js, how do I construct a query that matches items where a field is nil? Every permutation I've tried fails - either it's clearly matching on a string value (i.e. "null" or "nil") or it throws an error if I actually try to pass 'null'.
Any ideas? None of the below work.
filterBy: [{
fieldName: 'customerNumber',
comparator: 'EQUALS',
fieldValue: { value: "nil" }
}]
filterBy: [{
fieldName: 'customerNumber',
comparator: 'EQUALS',
fieldValue: { value: null }
}]
filterBy: [{
fieldName: 'customerNumber',
comparator: 'EQUALS',
fieldValue: { value: "null" }
}]
filterBy: [{
fieldName: 'customerNumber',
comparator: 'EQUALS',
fieldValue: { value: "" }
}]

I don't think there is any option to query for nil values in CloudKit. Also not from native code. I have tried a lot of predicates, but non seems to work.
You do have to be aware that CloudKit is a key-value store. When a value is nil, then the key won't be there in the record. There is no option to query for non existing keys.
The closest I have come to a good solution was with a predicate with the format "NOT myField => ''" sorry, don't know the format for .js
In the CloudKit CKQuery documentation there is nothing mentioned about nil fields.
In the documentation for NSPredicates there are sample's for nil values.
But it was already clear that CloudKit has implemented only a subset of the possibilities of NSPredicate (see CKQuery class reference)
I think the best way to handle this is by not using/depending on nil values. If you do need to check some nil status, then instead you could add an extra field that would represent that status.

Related

How to range over bson.D primitive.A slice mongo-go-driver?

My data structure is
{
_id: ObjectID,
...
fields: [
{ name: "Aryan" },
{ books : [ 1,2,3 ] },
]
}
In our application a user can define his own fields data structure but with a key value structure. So, we had no way of knowing the structure of the data.
So in our document struct we had
type Document struct {
Fields map[string]interface{}
}
as the second parameter returned by mongo was primitive.A ( []interface{} under the hood ), the individual item could have been an array, map, anything.
But we couldn't range over that for it being.
How can I get the individual values like the book ids [1,2,3] or the name value "Aryan" ?
After a couple of attempts to solving this, I was at a state where my current element it self is an interface{} ( [1,2,3] in this case ) and I couldn't get the individual 1,2,3s.
But finally managed to solve it
for k, val := range doc.Fields {
v := reflect.ValueOf(val)
switch reflect.TypeOf(t).Kind() {
case reflect.Slice:
// getting the individual ids
for i := 0; i < v.Len(); i++ {
fmt.Println(v.Index(i))
}
case reflect.String:
default:
// handle
}
}
Note: v.Index(i) returns a data type of Value .
to change the data type
v.Index(i).Interface().(string) // string
v.Index(i).Interface().(float64) // float
Ideally you should avoid working with interface{} type since it's very error prone and the compiler can't help you. The idiomatic way is to define a struct for your model with BSON tags like in this example`
type MyType struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Fields []Field `bson:"fields,omitempty"`
}
type Field struct {
Name string `bson:"name,omitempty"`
Books []int `bson:"books,omitempty"`
}
Field here is defined as the reunion of all possible fields which again is not ideal but at least the compiler can help you and developers know what to expect from the database document.

fliend createdAt in Prisma schema returns a null value when createUser() is called

When including a createdAt field in my datamodel.prisma schema the DateTime! returns a null value.
I am raising this on here so that if anyone else has the same problem, hopefully they will be able to find this post.
// in datamodel.prisma
type User {
id: ID! #id
trade_no: String!
name: String!
email: String!
createdAt: DateTime!
}
Error message looks like this "Reason: 'createdAt' Expected non-null value, found null."
In mongoDB the createdAt must be written as
type User {
id: ID! #id
trade_no: String!
name: String!
email: String!
created_at: DateTime! #createdAt
}
when used with Prisma (don't know if this is the case for other databases). Also, bear in mind that the #relation directive must have link: INLINE as an argument (the relationship is stored in the record, not in a separate table). Took me a while to work this out so I thought I'd put it here.
It's worth having a look at https://www.prisma.io/docs/releases-and-maintenance/features-in-preview/mongodb-b6o5/ for other specificities with Prisma & mongoDB.

Mongoose array required in schema validation not working

In my schema I need to have a propery that is an array that must be always not null and not undefined.
So I defined it required, but the validation is not working as I expected, because if I omit the property no error is throw.
In case of simple property (not an array) this work as I expected
const nodeSchema = new Schema({
address: { type: String, required: true },
outputs: { type: [String], required: true }
})
I think you can fix it adding a custom validator like this:
const nodeSchema = new Schema({
address: { type: String, required: true },
outputs: {
type: [String],
required: true,
validate: [(value) => value.length > 0, 'No outputs'],
}
})
I hope it helps you.
Arrays implicitly have a default value of [] (empty array).
This was the problem
Array implicitly have a default value of [] (empty array).
if you add default: undefined it will fix the issue.

Iterating through an array of strings, fetched from MongoDB

I'm using the MongoKitten library to fetch documents from mongoDB.
I have the following document in my mongoDB:
{
...
foo: ["A", "B"]
...
}
I can query the db, but I can't loop through the foo array of the returned documents. For instance, let's say that I save the results of my query into mongoDocs.
for Doc in mongoDocs {
print(Doc["foo"] as Any) // prints ["A", "B"]
var tempFoos = [String]()
for foo in Doc["foo"] { // gives error: Type 'Value' does not conform to protocol "Sequence"
print("Foo: " + foo)
tempFoos.append(foo)
}
}
I understand the error. Basically, my foo array doesn't conform to the Sequence protocol that allows me to loop over it. But how do I fix that?
Edit - Here's the code I'm using to fetch the mongoDocs. I've printed the results and used other properties from them. I just can't seem to iterate through this array.
mongoDocs = try self.geographiesCollection!.find(matching: q, projecting: projection, limitedTo: 100)
Here's the relevant function in the MongoKitten source code. The function returns Cursor<Document>
Here you can check out how a framework dev explained handling this situation. MongoKitten closed issue 27
here are some quotes from his explanation incase the link becomes invalid.
"MongoKitten BSON library always returns an enum (Value) when subscripting a document."
"A BSON array is really just a document with keys from 0 to x, so the enum case for array has a document as it's associated value. Because Value can also be, say, a double or a date, it doesn't conform to the Sequence protocol.
The easiest way to iterate over the array is by using the document convenience accessor on Value. This returns the underlying document if Value is either an array or document, or an empty document if it's something else. You can then iterate like this:"
for (key, val) in doc["vals"].document {
print("Value is \(val)")
}
Convert it into an array:
for Doc in mongoDocs {
guard let arr = Doc["foo"] as? [String] else { continue }
for foo in arr {
// do your things
}
}
I think you're using BSON 3. Value is an enum with multiple cases, which you can see here. Here's my stab at it:
for doc in mongoDocs {
guard case Value.array(let fooArray)? = doc["foo"] {
fatalError("doc[\"foo\"] is not an array")
}
print(fooArray)
}

Type of expression is ambiguous without more context Swift

I am getting a 'Type of expression is ambiguous without more context ' on this part of code from a project I am trying to upgrade to latest Swift version. I can't seem to figure it out. I tried different things but can't get it to work.
The problem is on the syntax of this line
let imageToDeleteParameters = imagesToDelete.map { ["id": $0.id, "url": $0.url.absoluteString, "_destroy": true] }
Full code:
extension TutorialCreationRequest: WebserviceParametrable {
func toParameters() -> [String: AnyObject] {
let imageParameters = images.map { ["url": $0] }
let imageToDeleteParameters = imagesToDelete.map { ["id": $0.id, "url": $0.url.absoluteString, "_destroy": true] }
return [
"title": title,
"is_draft": isDraft,
"difficulty": difficulty,
"duration": duration,
"cost": cost,
"user_id": userId,
"description": description,
"to_sell": toSell,
"images": [imageParameters, imageToDeleteParameters].flatMap { $0 }
]
}
}
This happens when you have a function with wrong argument names.
Example:
functionWithArguments(argumentNameWrong: , argumentName2: )
and You declared your function as:
functionWithArguments(argumentName1: , argumentName2: ){}
This usually happens when you changed the name of a Variable. Make sure you refactor when you do that.
This can happen if any part of your highlighted method or property is attempting to access a property or method with the incorrect type.
Here is a troubleshooting checklist, make sure:
the type of arguments match in the call site and implementation.
the argument names match in the call site and implementation.
the method name matches in the call site and implementation.
the returned value of a property or method matches in the usage and implementation (ie: enumerated())
you don't have a duplicated method with potentially ambiguous types such as with protocols or generics.
the compiler can infer the correct type when using type inference.
A Strategy
Try breaking apart your method into a greater number of simpler method/implementations.
For example, lets say you are running compactMap on an array of custom Types. In the closure you are passing to the compactMap method, you initialize and return another custom struct. When you get this error, it is difficult to tell which part of your code is offending.
For debugging purposes, you can use a for in loop instead of compactMap.
instead of passing the arguments, directly, you can assign them to constants in the for loop.
By this point, you may come to a realization, such as, instead of the property you thought you wanted to assign actually had a property on it that had the actual value you wanted to pass.
Not an answer to this question, but as I came here looking for the error others might find this also useful:
For me, I got this Swift error when I tried to use the for (index, object) loop on an array without adding the .enumerated() part ...
The compiler can't figure out what type to make the Dictionary, because it's not homogenous. You have values of different types. The only way to get around this is to make it a [String: Any], which will make everything clunky as all hell.
return [
"title": title,
"is_draft": isDraft,
"difficulty": difficulty,
"duration": duration,
"cost": cost,
"user_id": userId,
"description": description,
"to_sell": toSell,
"images": [imageParameters, imageToDeleteParameters].flatMap { $0 }
] as [String: Any]
This is a job for a struct. It'll vastly simplify working with this data structure.
I had this message when the type of a function parameter didn't fit. In my case it was a String instead of an URL.
Explicitly declaring the inputs for that mapping function should do the trick:
let imageToDeleteParameters = imagesToDelete.map {
(whatever : WhateverClass) -> Dictionary<String, Any> in
["id": whatever.id, "url": whatever.url.absoluteString, "_destroy": true]
}
Substitute the real class of "$0" for "WhateverClass" in that code snippet, and it should work.
I got this error when I put a space before a comma in the parameters when calling a function.
eg, I used:
myfunction(parameter1: parameter1 , parameter2: parameter2)
Whereas it should have been:
myfunction(parameter1: parameter1, parameter2: parameter2)
Deleting the space got rid of the error message
In my case, this error message shown when I don't added optional property to constructor.
struct Event: Identifiable, Codable {
var id: String
var summary: String
var description: String?
// also has other props...
init(id: String, summary: String, description: String?){
self.id = id
self.summary = summary
self.description = description
}
}
// skip pass description
// It show message "Type of expression is ambiguous without more context"
Event(
id: "1",
summary: "summary",
)
// pass description explicity pass nil to description
Event(
id: "1",
summary: "summary",
description: nil
)
but it looks always not occured.
I test in my playground this code, it show warning about more concrete
var str = "Hello, playground"
struct User {
var id: String
var name: String?
init(id: String, name: String?) {
self.id = id
self.name = name
}
}
User(id: "hoge") // Missing argument for parameter 'name' in call
For me the case was Type inference
I have changed the function parameters from int To float but did not update the calling code, and the compiler did not warn me on wrong type passed to the function
Before
func myFunc(param:Int, parma2:Int) {}
After
func myFunc(param:Float, parma2:Float) {}
Calling code with error
var param1:Int16 = 1
var param2:Int16 = 2
myFunc(param:param1, parma2:param2)// error here: Type of expression is ambiguous without more context
To fix:
var param1:Float = 1.0f
var param2:Float = 2.0f
myFunc(param:param1, parma2:param2)// ok!
My problem were the parameters without default value
I changed
let contaPadrao = RedeConta(
agencia: cPadrao?.agencia,
conta: cPadrao?.conta,
dac: cPadrao?.dac
)
to
let contaPadrao = RedeConta(
agencia: cPadrao?.agencia ?? "",
conta: cPadrao?.conta ?? "",
dac: cPadrao?.dac ?? ""
)
You have two " " before the =
let imageToDeleteParameters = imagesToDelete.map { ["id": $0.id, "url": $0.url.absoluteString, "_destroy": true] }
In my case it happened with NSFetchedResultsController and the reason was that I defined the NSFetchedResultsController for a different model than I created the request for the initialization (RemotePlaylist vs. Playlist):
var fetchedPlaylistsController:NSFetchedResultsController<RemotePlaylist>!
but initiated it with a request for another Playlist:
let request = Playlist.createFetchRequest()
fetchedPlaylistsController = NSFetchedResultsController(fetchRequest: request, ...
In my case, I ran into this error when I was creating a distribution build, and a class was referring to Debug only context method.
Something like this. Try compiling the below class for the Distribution build.
class MyClass {
func sayHello() {
helloWorld()
}
#if DEBUG
func helloWorld() {
print("Hello world")
}
#endif
}
Make sure if there is any delegate methods are available with extension, then implement those and error will disappear.
In my case, the arguments I was passing had optional String values. Providing a default value to fall back on ( in case the value is nil ) solved this issue for me.
I changed this -
router?.pushToDetailsScreen(
gitHubRepositoryOwnerName: gitHubRepositoryDetails?[index].owner?.login,
gitHubRepositoryName: gitHubRepositoryDetails?[index].name,
avatarUrl: gitHubRepositoryDetails?[index].owner?.avatar_url)
to this -
router?.pushToDetailsScreen(
gitHubRepositoryOwnerName: gitHubRepositoryDetails?[index].owner?.login ?? "",
gitHubRepositoryName: gitHubRepositoryDetails?[index].name ?? "",
avatarUrl: gitHubRepositoryDetails?[index].owner?.avatar_url ?? "")
This error could be shown due to multiple reasons. One of the most prominent reasons is a type mismatch. For example,
Suppose, parameter icons is a type of array and we passed an Enum as IconDismiss.
## Wrong
text.config = TextField.Config(isClearable: true, icons: IconDismiss)
## Correct
text.config = TextField.Config(isClearable: true, icons: [IconDismiss])
In my case it was very similar to what #scottyBlades said. I had changed a member variable name and not updated it in a callback and that caused the confusing/unhelpful error.
class SomeClass {
var newVarName: String
func doSomething() {
Async.makeCall { result in // << error shows here
self.oldVarName = result // not changing it to newVarName was the cause
}
}
}
As theEye's answer it is not an answer to this question, but as I also came here looking for the error im posting my case as others might find this also useful:
I got this error message when I was by error trying to calculate a value of two different types.
In my case I was trying to divide a CGFloat by a Double