1

I'm currently creating an e-commerce app for iOS and I'm having trouble deciding on how to structure my database for the scenario of a user searching for an item by "keywords". I wasn't sure if it would be better to store an array of the keywords or just having a string of key words for that item.

If you guys have any suggestions please let me know!

Thank you.

Here's the structure I have for a single item right now:

    "items": {
      "item1_id":{
          "brand_id": brandName_id,
          "itemName":.....,
          "price":.....,
          "keywords": ?
     }
  }
Brandon Cao
  • 79
  • 2
  • 9

2 Answers2

2

In Firebase, you can query using a single value or a value range, so constructing a single query to obtain items matching several keywords is not going to be possible. However, you could arrange your database so that you could easily query or a single keyword. You'd then need to combine several queries, etc.

You could arrange your data like this:

{
  "items": {
    "item1_id": {
      "brand_id": ...,
      "itemName": ...,
      "price": ...,
      "keywords": {
        "black": true,
        "t-shirt": true
      }
    }
  }
}

However, as explained in this answer, you would need to define an index for each keyword. To allow for efficient keyword-based queries, you could create your own mapping of keywords to items:

{
  "items": {
    "item1_id": {
      "brand_id": ...,
      "itemName": ...,
      "price": ...,
      "keywords": {
        "black": true,
        "t-shirt": true
      }
    }
  },
  "keywords": {
    "black": {
      "item1_id": true
    },
    "t-shirt": {
      "item1_id": true
    }
  }
}

The query for a keyword would be something like this:

let keyword = "black";
database.ref(`keywords/${keyword}`).once("value", (snapshot) => {
  snapshot.forEach((idSnapshot) => {
    database.ref(`items/${idSnapshot.key}`).once("value", (itemSnapshot) => {
      console.log(JSON.stringify(itemSnapshot.val()));
    });
  });
});

Having to maintain your own mapping of keywords to items is a little painful, but the queries will be fast. Also, Firebase's multi-location updates can make maintaining the keywords mapping a little easier. To create an item:

database.ref().update({
  "items/item1_id": {
    "brand_id": ...,
    "itemName": ...,
    "price": ...,
    "keywords": {
      "black": true,
      "t-shirt": true
    }
  },
  "keywords/black/item1_id": true,
  "keywords/t-shirt/item1_id": true
});

To change an item's keywords (remove black, add blue and leave t-shirt untouched):

database.ref().update({
  "items/item1_id/keywords": {
    "black": null,
    "blue": true
  },
  "keywords/black/item1_id": null,
  "keywords/blue/item1_id": true
});

And to delete an item:

database.ref().update({
  "items/item1_id": null,
  "keywords/blue/item1_id": null,
  "keywords/t-shirt/item1_id": null
});
Community
  • 1
  • 1
cartant
  • 57,105
  • 17
  • 163
  • 197
2

How about:

 items
      item0
        color: black
        type: t-shirt
        option: design
        keywords: black_t-shirt_design
      item1
        color: black
        type: hat
        option: design
        keywords: black_hat_design

then a simple query using startingAt and endingAt.

So for example, say the user is using a filter to narrow the results and wants to know about all of the black hats and doesn't care what the option parameter is:

itemsRef.queryOrdered(byChild: "keywords")
        .queryStarting(atValue: "black_hat")
        .queryEnding(atValue: "black_hat")

likewise if the user wanted to know about all of the clothing that's just black, you could query on the 'color' child for black.

But if they wanted all of the black hats with the design option

itemsRef.queryOrdered(byChild: "keywords")
        .queryStarting(atValue: "black_hat_design")
        .queryEnding(atValue: "black_hat_design")
Jay
  • 34,438
  • 18
  • 52
  • 81