I have an ORDER structure in ABAP that has another ITEMS structure within it which will contain multiple items per order.
I'm populating this structure through a SAP Gateway service, which works for an ORDER + a single ITEM.
{
"d": {
"Venueid": "dsfgg",
"Items" : {
"__metadata" : {
"type" : "ZGW_XXXX_SRV.Items"},
"Venueid" : "dsd",
"Type" : ""
}
}
}
However, what would be the syntax to provide an array of more than one ITEM?
The issue was because multiples can only be handled with the DEEP_INSERT method, not the normal CREATE.
Related
I have a value which needs to be compared with an array of values. Basically a user needs to check if it has the same item as another user. But I am struggling to solve this as how do I get the item of an array of users? Normally when you observe a value you do something like this:
Database.database().reference(withPath: "users/\(userID)/itemList").observeSingleEvent...
However, when it comes to an array of users itemList how can this be achieved if there are multiple ID's? I'd like compare a user item or items with other users item and check if they match in order to sort an array of users that have a match.
If there is already an example for this please help direct me there.
Update
This is how my data structure looks:
{
"users": {
"EWJGFYmVTzOiHgnq42ebhrg2fj": {
"firstName": "Friederike",
"itemList": [
2: true,
3: true,
0: true
]
},
"C076OYmVTzOiHgnq4wPQtY2XpED2": {
"firstName": "Ian",
"itemList": [
0: true,
1: true,
3: true
]
},
"Juoiuf0N6qNmkm32jrtu6X6UK62": {
"itemList": [
0: true
],
"firstName": "Jack"
}
}
}
Update 2.0
With the answer below I am able to query through the items table but still unable to query the keys that match as there can be multiple arrays and therefore I cannot use it to filter or anything.
Ok so with your current data structure you'd have to query all nodes under users and then compare the arrays, which is very inefficient. There isn't a straight forward or easy way to do that without modifying your structure. So I suggest you modify your data structure so that each item has a list of all users that have it. Something like this:
{
"items": {
"0": {
"EWJGFYmVTzOiHgnq42ebhrg2fj": "Friederike",
"C076OYmVTzOiHgnq4wPQtY2XpED2": "Ian",
"Juoiuf0N6qNmkm32jrtu6X6UK62": "Jack"
},
"1": {
"C076OYmVTzOiHgnq4wPQtY2XpED2": "Ian"
},
"2": {
"EWJGFYmVTzOiHgnq42ebhrg2fj": "Friederike"
}
//....
}
}
Depending on what you want to display you might want to store more information than just the users UID and username. You can query all the users that have the same items as you using a query like this:
let ref = Database.database().reference()
// assuming you already have the current users items stored in an array
for item in items {
ref.child("items").child(String(item)).observeSingleEvent(of: .value, with: { snap in
for child in snap.children {
let child = child as? DataSnapshot
if let key = child?.key, let name = child?.value as? String {
// do something with this data
}
}
})
}
Firebase database is noSQL, so data is meant to be denormalized or duplicated so that queries can be optimized. Firebase actually recommends that you avoid nesting data. Take a look at this question for more information.
Hope that helps
Code related to question asked in comments
Assuming you are storing the UID's or names of users with the same items in a string array you can prevent duplicates using .contains()
var namesWithMatchingItems = [String]()
if !namesWithMatchingItems.contains(nameYouJustFetched) {
namesWithMatchingItems.append(nameYouJustFetched)
}
I am currently trying to use Firebase, Flashlight and Swift to create an search function to retrieve a random object from my realtime database.
I am trying to perform the following query to Firebase at /search/request
var searchSettings : [Any] = []
if Settings.searchPackage != 99 {
searchSettings.append(["match" : Settings.searchPackage])
}
if Settings.searchCountry != .world {
if let region = Locale.current.regionCode {
searchSettings.append(["match" : region])
}
}
if Settings.searchGender != .All {
searchSettings.append(["match" : Settings.searchGender.rawValue])
}
let postData = [
"index" : "firebase",
"type" : "test",
"body" : [
"query" : searchSettings
]
] as [String : Any]
ref.setValue(postData, withCompletionBlock: { (error, reference) in
if error == nil {
FIRDatabase.database().reference().child("search/response").child(ref.key).observeSingleEvent(of: .childAdded, with: { (snapshot) in
if snapshot.exists() {
print("found random snapshot based on settings \(snapshot)")
}
})
}
})
The problem is, as Firebase described in the documentation it does currently support Arrays, therefor the content of "query" will be:
Flashlight will throw an error because it expects the "query" to contain "match" fields and not the indexes of an array of them.
How would I fix this? I want to be able to search based on multiple fields.
Technically, Flashlight doesn't care at all what you put inside the body tag; it simply passes it on to ElasticSearch. So if there is an error generated about the format, it's ElasticSearch that's doing the complaining.
What you're probably running into here is either a) ElasticSearch doesn't like that syntax, or Firebase's array-like behaviors are converting the array to an object.
Note that Flashlight will allow you to pass a JSON string in place of body. So if this is a result of the array-like behaviors, you can JSON.stringify() the query before passing it into ES, and it will come out the other end as intended.
If the problem is the ES syntax (as it appears to me) then you can simply run the queries directly against ES until they work, and then modify your client to submit correct syntax accordingly.
Take a look at this gist:
BodyQuery in Swift
I wrote this in my Android application project and I'm using this to build queries for ES. Here is equivalent in Java for Android ElasticSearch needs a json query, and you can create it easily using Maps (Android)/Dictionaries (iOS). Enjoy :)
I am trying to retrieve data from two tables in a database. I understand that if I want to read from a child I do this:
mDatabase = FirebaseDatabase.getInstance().getReference().child("Users");
So what do I do for two children?
My data looks like this:
I'll assume 2 possibilities for your question.
First: you want to retrieve a child of a child
appName{
"users" : {
"Bob" : {
"age" : 20
}
}
In this case to access a specific user you should do:
mDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child("Bob");
But if you mean that you have different child like: users and questions
appName{
"users" : {
"Bob" : {
"age" : 20
}
}
"questions" : {
"who am I?"
}
}
Then, you should make a reference to each one of them:
usersRef = FirebaseDatabase.getInstance().getReference().child("Users");
questionsRef = FirebaseDatabase.getInstance().getReference().child("questions");
"John" : {
"David" : {
"-KIMA0aPsujdAOpkzP0w" : {
"message" : "hallu",
"sender" : "10154053432889835",
"time" : 1463898873196
}
}
},
"Harry" : {
"Christina" : {
"-KIMA0aPsujdAOpkzP0v" : {
"message" : "hallu",
"seen" : true,
"sender" : "self",
"time" : 1463898873195
}
},
"Pierce" : {
"-KILZ_GH7Ji9hQYNK-6p" : {
"message" : "Eli there.",
"seen" : true,
"sender" : "179914035712208",
"time" : 1463888795301
},
"-KIM8yPz2UDOZwHEg_nn" : {
"message" : "hahjajak",
"seen" : true,
"sender" : "self",
"time" : 1463898597847
},
}
I wanted to query the count of nodes where "seen" key has value "true" of top node which is John OR Harry There are multiple child node inside it and each child node has multiple child node which has automatic id set.
I just want to know the count of objects which has "seen" key set to true and also count of objects which has "seen" key set to false
I can extract all the values in node as follows:
ref.observeSingleEventOfType(.Value, withBlock: { snap in
for (key,value) in snap.value as! NSDictionary {
}
})
I can loop through the dictionary and count the number of objects manually. But that is not too computationally or data efficient as firebase is volume based.
What I want is to know if there is any query to count the number of objects whose "seen" key in root node is "true" or whose "seen" key in root node is "false".
UPDATE:
Data Structure
John and Harry are user unique ID. and the node David which is immediate child of John node is unique ID of person who the user has chatted with earlier.
And the KIMA0aPsujdAOpkzP0w node represent a unique message from user John to/from David.
So what i wanted was to count the number of messages from David to John not seen by John
If you want to get only the "seen" value, you should reconsider your database structure and denormalize where possible to make reading as fast as you can.
Keeping your structure to get "seen" value, each time you read you have to get the entire node and loop through it to get the value, downloading unnecessary data, wasting processing time and making overall operation slower.
You should create a new node and store just the "seen" value the way you are going to get it later. Lets say, the best way to structure your database is based on which read operations are going to do and what data do you need in those operations.
You shouldn't worry about duplicating data. Remember that Firebase has the "updateChildren" method that allows you to update data in different nodes in a single operation.
For more info you can read the docs about structuring data here: https://firebase.google.com/docs/database/android/structure-data
Cheers!
Not sure if this is the most efficient way to handle it, but for a rapid prototype I've been searching for the answer to this problem as well. I settled on using this strategy to isolate child nodes of the data structure:
ref.observeSingleEventOfType(FIRDataEventType.Value, withBlock: { snapshot in
for (key,value) in snapshot.value as! NSDictionary {
if (key as! String == "John/David/etc")
{
let newRef = FIRDatabase.database().reference().child("John").child(key as! String)
newRef.observeSingleEventOfType(FIRDataEventType.Value, withBlock: { snapshot in
for (childKey, childValue) in snapshot.value as! NSDictionary{
//do whatever you want with child values/etc
}
})
}
}
})
Keep in mind I am VERY new to Firebase on iOS and they just changed their documentation so I'm working through it as I can. I'm sure there are way better ways to accomplish accessing child data but this worked for my MVP so I went with it.
EDIT: This assumes that your original reference is aimed at the part of the data tree that you want to target. For example:
let ref = FIRDatabase.database().reference().child("John")
That way when you did ref.observeSingle..etc, it would look for the values underneath that child object, instead of the entire tree.
So, I have an api call that'll output some raw json in the format below...
A bit messy, but I'm only interested in the Mapping portion of this json. If I had access to the raw data, I'd serialise the json cut to the dictionary / array I want to iterate through.. However the client is using restkit and this doesn't seem quite as easy as I'm imagining it....
Also What should I do with the Images section? Again, if was doing this with serialised json, I could open up the dictionary and set what's inside to an object with name description etc... can I do this as well?
{
"rsp": {
sn : "SerialNumber",
name : "Service Name",
from : "2000-01-01T00:00:00.000+01:00",
to : "2000-01-02T00:00:00.000+01:00",
mappings : {
"mapping" : {
"1" : {
from : 2000-06-01T00:01:00.000+01:00
to : 2000-06-01T01:02:00.000+01:00
content : {
name : "name"
description : "description"
images : {
image : "b47ab5a8.png"
}
}
},
"2" : {
from : 2000-06-01T00:01:00.000+01:00
to : 2000-06-01T01:02:00.000+01:00
content : {
name : "name"
description : "description"
images : {
image : "b47ab5a8.png"
}
}
},
// etc...
My question is
// what goes here
RKObjectMapping *itemMapping = [RKObjectMapping mappingForClass:[MYItem class]];
[itemMapping addAttributeMappingsFromDictionary:#{#"description":#"itemDescription",
#"name":#"name"}];
And how do I add the image to MYItem?
For the image your mapping is something like:
[itemMapping addAttributeMappingsFromDictionary:#{#"description":#"itemDescription",
#"name":#"name",
#"images.image":#"image"}];
i.e. key paths work
But, not that they only work for dictionaries. You can't index into arrays arbitrarily in the same way.
The key path is also in the response descriptor and that's how you drill down to the mapping, i.e. rsp.mappings.mapping (again, because it's dictionaries).