0

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.

Chace
  • 561
  • 10
  • 28
  • To do this your probably have to adjust your data structure. Please post it so I can help. – DoesData Jan 09 '18 at 11:47
  • @DoesData please see updated question. So basically you are user Juoiuf0N6qNmkmUM4qYlM6X6UK62 and you want to only query users with an itemList that matches yours. – Chace Jan 09 '18 at 14:42

1 Answers1

1

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)
}
DoesData
  • 6,594
  • 3
  • 39
  • 62
  • Very helpful. Are you suggesting I have a separate table of the items value and users that have items? Also, how would storing the items to the user look like on your data structure? – Chace Jan 10 '18 at 15:42
  • 2
    Storing the items to the user doesn't change. You just create the structure above so that each item also has a list of all the users who have it. Remember we are duplicating data. Then you retrieve the user's items stored at "users"->"uid"->"items", iterate over that list and for each item retrieve the users that also have that item. That's how my query above is designed. – DoesData Jan 10 '18 at 16:03
  • I've just been attempting your solution. Just wondering, is it better to save the user to item as items > 0 > users > uid instead of your example which is items > 0 > uid. That way when I loop to the item to get it's name, I'm not getting all the users ID. – Chace Jan 10 '18 at 17:23
  • They why you implement this depends on what information you want to get. I don't really have any idea what information you're storing or why. You should modify the data structure so it fits your needs without making things too complex. – DoesData Jan 10 '18 at 17:25
  • I understand, I'm thinking this structure might not work for me as let's say the user removes the item from their list then it'll also have to check through the items table. – Chace Jan 11 '18 at 13:35
  • Correct, but you can easily delete it since you know the item name and the UID of the user so that’s not a problem. You could also use an on delete cloud trigger for the current users structure and have that delete the item from items on the back end – DoesData Jan 11 '18 at 13:43
  • When fetching data and comparing how to avoid duplicate results? I'm able to get it to check which user shares the same item, but as the other user is in several item then it displays that user as many as it matches with. – Chace Jan 12 '18 at 13:52
  • This question is a mess. You’re not asking questions that are not related to the original question and you’re providing no relevant code. You’re suppose to ask one question. If you’re having trouble preventing duplicates that’s a different question and requires the relevant code to be posted in order for an answer to be provided. – DoesData Jan 15 '18 at 17:32
  • Sorry to continue the thread. But I am struggling to append the list of users keys that has items that matches. I've been able to loop through the different items. But it gives me different arrays as it loops however amount of items I'm looking for, and I don't know how to merge the arrays together so that I can check, filter and use it. I have this method `self.arrayOfAllKeys.append(contentsOf: self.arrayOfUserKeys)` – Chace Jan 25 '18 at 01:46
  • Again this is not related to the original question. Without code how do you expect me or anyone else to help you. I have yet to see the query you're performing. Post a new question and explain the current issue then maybe someone can help. – DoesData Jan 25 '18 at 15:02
  • Also half of the questions you asked do not have an accepted answer... you should fix that. – DoesData Jan 25 '18 at 15:04
  • Please see my new question: https://stackoverflow.com/questions/48490027/store-values-from-multiple-loops-into-an-array – Chace Jan 28 '18 at 18:44