graphql-to-mongodb icon indicating copy to clipboard operation
graphql-to-mongodb copied to clipboard

Handling ObjectId in filter

Open sscots opened this issue 5 years ago • 4 comments

Say I want to get a specific person record and filter by _id

person (
   filter: {
       _id: { EQ: "5e1e2d653a32a05f51f621c1" }
   }
) {
   name { 
      lastName
   }
   age
}

Currently that will generate a filter like so

{ _id: { '$eq': '5e1e2d653a32a05f51f621c1' }

Can you detect when "_id" is used and make it essentially do this instead?

{ _id: { '$eq': new ObjectId('5e1e2d653a32a05f51f621c1') }

sscots avatar Jan 23 '20 21:01 sscots

Sorry for the overdue response.

That sounds like a feature worth adding to the package. I'm not sure when I'll get around to it, but in the meantime you can:

  • Add a PR
  • Since querying by _id about makes every other filter obsolete you can create a field like:
    id: {
        type: PersonType,
        args: { _id: { type: new GraphQLNonNull(GraphQLString) } },
        resolve: async (obj, args, { db }: { db: Db }, info) => {
            const projection = getMongoDbProjection(info, PersonType);
            return await db.collection('people').find({ _id: new ObjectId(args._id) }, { projection }).toArray();
        }
    }
    

yoavkarako avatar May 06 '20 11:05 yoavkarako

As long as your scalar type is ObjectId and not string it works just fine. same with date BTW.

or make your own... ObjectId

import { GraphQLScalarType, Kind } from "graphql";
import { ObjectId } from "mongodb";

export const ObjectIdScalar = new GraphQLScalarType({
  name: "ObjectId",
  description: "Mongo object id scalar type",
  parseValue(value: string) {
    return new ObjectId(value); // value from the client input variables
  },
  serialize(value: ObjectId) {
    return value.toHexString(); // value sent to the client
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.STRING) {
      return new ObjectId(ast.value); // value from the client query
    }
    return null;
  },
});

and date...

import { GraphQLScalarType, Kind } from "graphql";

export const GraphQLISODateTime = new GraphQLScalarType({
  name: "DateTime",
  description:
    "The javascript `Date` as string. Type represents date and time as the ISO Date string.",
  parseValue(value: string) {
    return new Date(value);
  },
  serialize(value: Date) {
    if (!(value instanceof Date)) {
      throw new Error(`Unable to serialize value '${value}' as it's not instance of 'Date'`);
    }
    return value.toISOString();
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.STRING) {
      return new Date(ast.value);
    }
    return null;
  },
});

code-is-art avatar May 23 '20 15:05 code-is-art

As long as your scalar type is ObjectId and not string it works just fine. same with date BTW.

or make your own... ObjectId

import { GraphQLScalarType, Kind } from "graphql";
import { ObjectId } from "mongodb";

export const ObjectIdScalar = new GraphQLScalarType({
  name: "ObjectId",
  description: "Mongo object id scalar type",
  parseValue(value: string) {
    return new ObjectId(value); // value from the client input variables
  },
  serialize(value: ObjectId) {
    return value.toHexString(); // value sent to the client
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.STRING) {
      return new ObjectId(ast.value); // value from the client query
    }
    return null;
  },
});

and date...

import { GraphQLScalarType, Kind } from "graphql";

export const GraphQLISODateTime = new GraphQLScalarType({
  name: "DateTime",
  description:
    "The javascript `Date` as string. Type represents date and time as the ISO Date string.",
  parseValue(value: string) {
    return new Date(value);
  },
  serialize(value: Date) {
    if (!(value instanceof Date)) {
      throw new Error(`Unable to serialize value '${value}' as it's not instance of 'Date'`);
    }
    return value.toISOString();
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.STRING) {
      return new Date(ast.value);
    }
    return null;
  },
});

I also am trying to learn graphql with this library and encountered the same problem. Yup this helped me

burner986 avatar May 31 '20 18:05 burner986

When I try the above custom scalar type code, I receive...

Argument type {name: string, description: string, parseValue(=): , serialize(): , parseLiteral(): ( | null)} is not assignable to parameter type GraphQLScalarTypeConfig<*, *>

I think that's just a warning from my IDE. The code compiles, but at runtime I receive the error... TypeError: graphQLType.getFields is not a function

thardy avatar Jun 12 '20 13:06 thardy