graphql-compose / graphql-compose-mongoose

Mongoose model converter to GraphQL types with resolvers for graphql-compose https://github.com/nodkz/graphql-compose
MIT License
708 stars 94 forks source link

Field not available in filter for obscure reasons #368

Closed ziedHamdi closed 3 years ago

ziedHamdi commented 3 years ago

Hi,

I have a simple example where the field 'created':Date is not filtrable: I get the following error message graphQl error : Field "created" is not defined by type FilterFindOneentitygroupstathistoryOperatorsInput. Here's my mongoose schema:

import mongoose, {Schema} from 'mongoose';

const EntityGroupStatHistory = new Schema({
    _id: {type: String, required: true, unique: true},
    entityGroupId: String,
    commentCount: Number,
    commentUserCount: Number,
    empathyCount: Number,
    joinedCount: Number,
    created: Date,
    visitStats: [{_id: 'ObjectId', totalVisits: Number}]
})

created is indexed but not unique

export default mongoose.model('entitygroupstathistory', EntityGroupStatHistory)

The query that fails s this:

const ENTITY_GROUP_STATS = gql`
query entityGroupStatHistoryOne($entityGroupId:String!, $created:Date!) {  
  entityGroupStatHistoryOne(filter:{entityGroupId:$entityGroupId, _operators :{created:{gt:$created}}}) {
    _id
    entityGroupId
    commentCount
    commentUserCount
    empathyCount
    joinedCount
    created
    visitStats {
        totalVisits
    }
  }
}`

More details: Actually the table is a materialized view created by this script:

import logger from "../../lib/logger";

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
import DB_CONFIG from '../../server/constants/database'
/*
 * entitygroupstathistory has a non MongoId _id field!!!
 */

const agg = [
    {
        '$match': {
            'entityGroupId': {
                '$exists': true
            }
        }
    }, {
        '$addFields': {
            'timeId': {
                '$concat': [
                    {
                        '$dateToString': {
                            'format': '%Y-%m-%d',
                            'date': new Date()
                        }
                    }, '_', '$entityGroupId'
                ]
            }
        }
    }, {
        '$group': {
            '_id': '$timeId',
            'entityGroupId': {
                '$first': '$entityGroupId'
            },
            'commentCount': {
                '$sum': '$stats.COMMENT.actionCount'
            },
            'commentUserCount': {
                '$sum': '$stats.COMMENT.userCount'
            },
            'empathyCount': {
                '$sum': '$stats.USER_LIKE.userCount'
            },
            'joinedCount': {
                '$sum': '$stats.SAME_ISSUE.userCount'
            }
        }
    }, {
        '$addFields': {
            'created': new Date()
        }
    }, {
        '$lookup': {
            'from': 'entitygroupbyvisitsmin',
            'localField': 'entityGroupId',
            'foreignField': '_id',
            'as': 'visitStats'
        }
    }, {
        '$merge': {
            'into': 'entitygroupstathistory',
            'on': '_id',
            'whenNotMatched': 'insert',
            'whenMatched': 'replace'
        }
    }
];

export async function findCollection(db, collectionName) {
    const existingCollections = await db.collections()
    return existingCollections.find((col) => collectionName == col.s.namespace.collection)
}

MongoClient.connect(
    DB_CONFIG.URL,
    {useNewUrlParser: true, useUnifiedTopology: true},
    async function (connectErr, client) {
        assert.equal(null, connectErr);
        const db = client.db('weally');
        const collectionName = 'entitygroupstathistory';
        const found = await findCollection(db, collectionName);
        if(!found) {
            const entitygroupstathistory = await db.createCollection(collectionName)
            await entitygroupstathistory.createIndex({'created':-1})
        }
        const coll = db.collection('complaints');
        await coll.aggregate(agg).toArray();
        client.close();
    });

And here's a sample document:

{
   "_id":"2021-08-20_611e5e9eb07ade298c8629f4",
   "entityGroupId":"611e5e9eb07ade298c8629f4",
   "commentCount":2,
   "commentUserCount":2,
   "empathyCount":1,
   "joinedCount":1,
   "created":{
      "$date":"2021-08-20T12:57:42.284Z"
   },
   "visitStats":[
      {
         "_id":"611e5e9eb07ade298c8629f4",
         "totalVisits":6,
         "entityGroupId":{
            "$oid":"611e5e9eb07ade298c8629f4"
         },
         "entityGroup":[
            {
               "_id":{
                  "$oid":"611e5e9eb07ade298c8629f4"
               },
               "isHeadOffice":true,
               "categoryTree":[

               ],
               "types":[
                  "department_store",
                  "hardware_store",
                  "grocery_or_supermarket",
                  "electronics_store",
                  "furniture_store",
                  "home_goods_store",
                  "food",
                  "point_of_interest",
                  "clothing_store",
                  "store",
                  "establishment"
               ],
               "issueCount":0,
               "externalId":"ChIJDZop4q1_54gR0k1wqo3X8iY",
               "origin":"GMAPS",
               "kind":"SERVICE",
               "name":"Walmart Supercenter",
               "mapsUrl":"https://maps.google.com/?cid=2806542521255087570",
               "address":"8990 Turkey Lake Rd, Orlando, FL 32819, USA",
               "phone":"(407) 351-2229",
               "web":"https://www.walmart.com/store/4332-orlando-fl?cn=Tracking_local_pack_1",
               "location":{
                  "type":"Point",
                  "coordinates":[
                     -81.4764715,
                     28.4399415
                  ],
                  "_id":{
                     "$oid":"611e5e9eb07ade298c8629f5"
                  }
               },
               "uniqueName":"ChIJDZop4q1_54gR0k1wqo3X8iY",
               "userList":[

               ],
               "phones":[

               ],
               "emails":[

               ],
               "createdAt":{
                  "$date":"2021-08-19T13:37:34.852Z"
               },
               "updatedAt":{
                  "$date":"2021-08-19T13:37:34.898Z"
               },
               "__v":0,
               "asEntityId":"611e5e9eb07ade298c8629f6"
            }
         ]
      }
   ]
}
ziedHamdi commented 3 years ago

Actually, the plugin doesn't look into indexes in the db, it only looks at the mongoose definition. modifying the schema this way fixed the issue: created: {type:Date, index: true},