Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to query firestore() for graphQL resolver?

I'm combining a GraphQL app with my existing Firebase project and am having a lot of problems getting the queries to correctly get data from the firestore().

So far I have the mutations working correctly, but when I go to query the data I can't get the firestore().get() snapshot into a form that graphQL will recognize.

so far it looks like this:

const {GraphQLObjectType,
  GraphQLString,
  GraphQLBoolean,
  GraphQLFloat,
  GraphQLSchema,
  GraphQLID,
  GraphQLList,
  GraphQLNonNull} = require("graphql");
const admin = require('firebase-admin');
const functions = require('firebase-functions');


admin.initializeApp(functions.config().firebase);

//Models
const Room = admin.firestore().collection('room');
const Position = admin.firestore().collection('position');
const Plant = admin.firestore().collection('plant');
const PlantInfo = admin.firestore().collection('plantInfo');

const RoomType = new GraphQLObjectType({
  name: "Room",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    description: { type: GraphQLString },
    floor: { type: GraphQLString },
    building: { type: GraphQLString },
    positions: {
      type: new GraphQLList(PositionType),
      resolve(parent, arg) {
        //return _.filter(positions, {inRoomId:parent.id})
        return Position.orderByChild('inRoomId').equalTo(parent.id);
      }
    }
  })
});

const PositionType = new GraphQLObjectType({
  name: "Position",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    description: { type: GraphQLString },
    exposure: { type: GraphQLString },
    size: { type: GraphQLString },
    inRoom: {
      type: RoomType,
      resolve(parent, args) {
        //return _.find(rooms, {id:parent.inRoomId})
        return Room.child(parent.inRoomId);
      }
    }
  })
});

const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    room: {
      type: RoomType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        //code to get data from db/othersourse
        //return _.find(rooms, {id: args.id});
        return Room.child(args.id);
      }
    },
    position: {
      type: PositionType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        //code to get data from db/othersourse
        //return _.find(positions, {id: args.id})
        return Position.child(args.id);
      }
    },
    rooms: {
      type: new GraphQLList(RoomType),
      resolve(parent, args) {
        //return rooms
        return Room.get().then(snapshot => {snapshot.forEach(doc => {return doc})})

      }
    },
    positions: {
      type: new GraphQLList(PositionType),
      resolve(parent, args) {
        //return positions
        return Position.get().then(doc => console.log(doc)).catch(err => console.log('Error getting document', err));
      }
    }
  }
});

const Mutation = new GraphQLObjectType({
  name: "Mutation",
  fields: {
    addRoom: {
      type: RoomType,
      args: {
        name: { type: new GraphQLNonNull(GraphQLString) },
        floor: { type: new GraphQLNonNull(GraphQLString) },
        building: { type: new GraphQLNonNull(GraphQLString) }
      },
      resolve(parent, args) {
        let room = {
          name: args.name,
          floor: args.floor,
          building: args.building
        };
        return Room.add(room);
      }
    },
    addPosition: {
      type: PositionType,
      args: {
        name: { type: new GraphQLNonNull(GraphQLString) },
        exposure: { type: new GraphQLNonNull(GraphQLString) },
        size: { type: new GraphQLNonNull(GraphQLString) },
        inRoomId: { type: new GraphQLNonNull(GraphQLString) }
      },
      resolve(parent, args) {
        let position = {
          name: args.name,
          exposure: args.exposure,
          size: args.size,
          inRoomId: args.inRoomId
        };
        return Position.add(position);
      }
    }
  }
});

module.exports = new GraphQLSchema({
  query: RootQuery,
  mutation: Mutation
});

Under the RootQuery -> Rooms I'm trying to get a graphQL query to return all the rooms in my 'room' collection. I have been able to get it to console.log() a list of documents using:

return Room.get()
.then(snapshot => {
snapshot.forEach(doc => {
        console.log(doc.id, " => ", doc.data());

But getting this into an array has so far eluded me. Any help is really appreciated.

like image 681
Lloyd Richards Avatar asked Aug 31 '19 11:08

Lloyd Richards


People also ask

Can I use GraphQL with firestore?

Using GraphQL with Firestore would not make things faster -- since Firebase SDKs already talk directly to the backend database the connection is as fast as it can be. GraphQL can be used with Firestore, but you would mostly do so if you had a specific reason to prefer the data composition or query patterns it enables.

Can you query firestore?

Cloud Firestore provides powerful query functionality for specifying which documents you want to retrieve from a collection or collection group. These queries can also be used with either get() or addSnapshotListener() , as described in Get Data and Get Realtime Updates.

Can you use GraphQL with firebase?

Use mutations to add and update data Finally, we'll add new data to the Firebase Realtime Database using GraphQL. The REST API from Firebase allows you to both insert and update data. The request returns the ID of the updated or inserted value when successful.


1 Answers

Seeing as no one was able to answer this, I ended up figuring it out for myself :p

So resolve functions relating to getting a collection of related data for example positions. the following works:

first you need a function to convert the snapshots into an array as this is what graphQL is expecting. This also allows your to seperate the id and add it in with the array item:

const snapshotToArray = (snapshot) => {
  var returnArr = [];

  snapshot.forEach((childSnapshot)=> {
      var item = childSnapshot.data();
      item.id = childSnapshot.id;

      returnArr.push(item);
  });

  return returnArr;
};

Next when getting the data you use .get() which returns a promise (and error) which can be passed into the snapshotToArray().

return Position.get().then((snapshot) => {
          return snapshotToArray(snapshot);
        }) 

For resolve functions that only call on one dataset for example inRoom. Its similar to the first one except using .where() and seperating the id and data() in the snapshot functions:

return Room.doc(parent.inRoomId).get().then((snapshot) => {
          var item = snapshot.data();
          item.id = snapshot.id;
          return item;
        })

Just incase someone else runs into the same problem :)

like image 80
Lloyd Richards Avatar answered Oct 21 '22 15:10

Lloyd Richards