Jamie T
Jamie T

Reputation: 31

In ARRAY usage in Flutter Firebase

I want to have a user select several sports teams from an NHL list or more specifically firebase to act like tags.

In a document I want to include an array that might have the tags of a story, #leafs, #senators #nhl.

Now I want to have the user interested in say #leafs #canadiens #nhl #ohl

I plan on storing the two in an array,

in Flutter

interestArray = ["leafs","canadiens",nhl,"ohl"] 

So how do I,

get from Firebase interestArray from the array field "storyTags"?

  .where('storyTags', arrayContains: interestArray )

Is this supposed to work?

Upvotes: 0

Views: 5775

Answers (2)

Wesley Tarle
Wesley Tarle

Reputation: 11

We recently announced that Cloud Firestore supports two new kinds of queries: "in" and "array-contains-any". They let you find documents with any of several values (up to 10).

That might help!

Upvotes: 0

Rich Gowman
Rich Gowman

Reputation: 44

Unfortunately, 'arrayContains' can only take a single value, rather than an array. So you could test .where('storyTags', arrayContains: 'leafs') but not 'leafs', 'canadiens'

However, a similar question has been asked before: Firestore search array contains for multiple values. (tl;dr: Use a map.)

Adapting that solution might result in a schema like:

Stories:
  <docid>:
    title: "Leafs to play Canadiens"
    tags: {
      "leafs": true,
      "canadiens": true,
      "nhl": true
    }

And then to query it for all stories involving both the leafs and the canadiens, you'd use something like:

db.collection("Stories")
  .where("tags.leafs", "==", true)
  .where("tags.canadiens", "==", true);

(Note that Firestore does not support logical 'OR' queries; to do that, you'd need to issue separate queries and then merge the results. https://firebase.google.com/docs/firestore/query-data/queries#query_limitations)

Update in response to comment:

As mentioned above, it's unfortunately not possible to perform a logical 'OR' query. So to fetch all stories tagged with either team, you'd need to do something like this (in javascript):

var leafsSnapshot = await db.collection("Stories").where("tags.leafs", "==", true).get();
var habsSnapshot = await db.collection("Stories").where("tags.canadiens", "==", true).get();

// Concatenate the results together and log the story titles.
var stories = leafsSnapshot.docs.concat(habsSnapshot.docs);

// This won't quite work:
//
//     stories.forEach(story => console.log(story.get("title")));
//
// It won't de-duplicate stories, so any story that's tagged with *both*
// will be printed twice.

var seen = new Set([])
stories.forEach(story => {
  if (!seen.has(story.id)) {
    seen.add(story.id);
    console.log(story.get("title"));
  }
});

Alternatively, if you're not interested in 'AND' queries, you could go back to using arrayContains and follow a similar approach as above. i.e.:

var leafsSnapshot = await db.collection("Stories").where("storyTags", "arrayContains", "leafs").get();

// the rest is the same.

Upvotes: 1

Related Questions