1

using swift and firebase I have a list of data like so

{
"posts" : {
 "-KHbULJcKqt9bSpxNO9k" : {
  "author" : "Michele",
  "postText" : "tags as arrays?",
  "tag" : [ "HELLO", "WHAT'S UP?", "TEST" ]
}

with many more post. I want to search by tag and if a post contains the search term as a tag return the whole post. Ive been able to do this with strings using queryEqualToValue: but haven't been able to solve it for an array. Any point in the right direction is appreciated thank you.

This is what my save function looks like

func createNewPost(post: Dictionary<String, AnyObject>, tags: [String]) {
    let firebaseNewPost = POST_REF.childByAutoId()
    let firebaseTag = Firebase(url: "\(POST_REF)/\(firebaseNewPost.key)/tag")

    print(firebaseTag)


    firebaseNewPost.setValue(post)

    for tag in tags {
        let tagID = firebaseTag.childByAutoId()

        tagID.setValue(tag)
    }
}

Now I need help with searching through the data and retrieving certain post based on what a user searches for. This is what I was using when it was just one tag and it was a just a string.

    func loadTaggedShit(searchTerm: String) {

    DataService.dataService.POST_REF.queryOrderedByChild("tag").queryEqualToValue(seachTerm).observeEventType(.ChildAdded, withBlock: { snapshot in
        self.posts = []

        if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
            for snap in snapshots {
                if let postDictionary = snap.value as? Dictionary<String, AnyObject> {
                    let key = snap.key
                    let post = Post(key: key, dictionary: postDictionary)

                    self.posts.insert(post, atIndex: 0)
                }
            }
        }

        self.tableView.reloadData()


    })

}

also the data now looks like this

"posts":{
 "-KHj_bDJmZJut7knKoUX" : {
  "author" : "Michele",
  "postText" : "what's up",
  "tag" : {
    "-KHj_bDJmZJut7knKoUY" : "HEY"
   }
 }
}

1 Answers1

1

Firebase arrays are very situational and really should be avoided if possible.

Array's in code are very powerful data constructs but they just don't work well within a JSON structure. If they are modified, say, removing a node, that index will be removed as well. That leaves the array with 'holes' e.g. 0, 1, 2, 4, 5, 7 etc. So, create yourself a tags child node within your post node, and then child nodes with keys created with childByAutoId

"posts" : {
 "-KHbULJcKqt9bSpxNO9k" : {
    "author" : "Michele",
    "postText" : "tags as arrays?",
    "tags"
       tag_id_0
         tag_title: "HELLO"
       tag_id_1
         tag_title: "WHAT'S UP?"
       tag_id_2
         tag_title: "TEST"
}

You might even consider creating a separate tags node and reference it within the posts node - especially if they are going to be re-usable.

Edit:

Based on some additional information, a different structure will be in order because the OP needs to query for posts that contain a specific tag and the tags are in fact reusable and not specific to a post:

posts
  -KHbULJcKqt9bSpxNO9k
    author: "Michele"
    postText: "tags as arrays?"
    tags
      tag_id_1: true
      tag_id_2: true
  -JPHJSojo91920LLK0J
    author: "Larry"
    postText: "NO, don't use arrays"
    tags
     tag_id_2: true

tags
  tag_id_0
    tag_title: "HELLO"
  tag_id_1
    tag_title: "WHAT'S UP?"
  tag_id_2
    tag_title: "TEST"

And then the code to receive all posts that use the TEST tag, tag_id_2

This is called a Firebase Deep Query

postsRef.queryOrderedByChild("tags/tag_id_2").queryEqualToValue(true)
        .observeSingleEventOfType(.Value, withBlock: { snapshot in
    print(snapshot)
})
Jay
  • 34,438
  • 18
  • 52
  • 81
  • 1
    Thank you Jay the post are not going to be modified once the user has posted it so would that change how you would do this? – MicheleRuocco May 13 '16 at 18:23
  • 1
    @Michi314 If they are specific to the post and will not be changed then use the Firebase structure I posted. That way they are query-able, loadable and are easy to work with in general – Jay May 13 '16 at 18:34
  • 1
    how would you go about saving the tags I tried but got the error no firebase namespace specified. This is the function that I made func createNewPost(post: Dictionary, tags: [String]) { let firebaseNewPost = POST_REF.childByAutoId() let firebaseTag = Firebase(url: "\(firebaseNewPost.key)/tags") firebaseNewPost.setValue(post) for tag in tags { let tagID = firebaseTag.childByAutoId() tagID.setValue(tag) } } – MicheleRuocco May 14 '16 at 13:54
  • @Michi314 It's best practice to not post code in comments. The tag_is_0, tag_id_1 etc are nodes created with childByAutoId if that helps. Can you update your original question with your followup question? – Jay May 14 '16 at 14:03
  • sorry about that I just figured it out but i'll update it with my new code could you also help with querying the data and finding specific post? Thank you – MicheleRuocco May 14 '16 at 14:08
  • Ive updated the original question could you please take a look? – MicheleRuocco May 14 '16 at 20:05
  • @Michi314 Your updated question has a sentence that's cut off - 'retrieving certain post based on what a user. '. We can help you with the query but need to know what parameters you are query'ing for (i.e. you want to find posts where the author is Michele?) – Jay May 14 '16 at 23:35
  • Based on tags the user searches for. So going through all post and pulling the ones that contain a tag = to the string. – MicheleRuocco May 14 '16 at 23:41
  • @Michi314 Your above comment said the tags were specific to the post. If you are searching for multiple posts with the same tag, then they are not specific to the post. I have updated my answer with a structure that will fit that requirement and also the code to make it happen. – Jay May 15 '16 at 14:20
  • If i use this structure then every time a user creates a new post it would have to go through every single tag and check whether it exist and is true. wouldn't that slow down everything if there are thousands of tags in the database? – MicheleRuocco May 15 '16 at 17:11
  • @Michi314 Nope, Firebase is blisteringly fast and this task is exactly what it excels at. Your initial question was to retrieve all of the posts that contain a tag. Step one is to get the tag_id for the tag you want, the second step is to query the posts for that tag id. That whole process would take a fraction of second - even with thousands of tags and posts. Your above comment/question would have even faster result as if the tag doesn't exist in the tags node, the query would be 'virtually instantaneous'. – Jay May 15 '16 at 23:22
  • @Michi314 To your comment: whenever you query a set of data, it's always 'going through every single tag' - that's the function of a query! It will *only* exist if it's true in the tags node. If there's going to be millions of tags, it's easy to divide that up: alphabetically! a_tags, b_tags, c_tags. Each child tag would start with the letter A, B, C etc. Then to query, capture the first letter of the tag you want to search for and search only that node. Search for Hello in the h_tags node. There's other options as well, but I wouldn't worry about Firebase performance for this situation. – Jay May 15 '16 at 23:34