提问者:小点点

跨mongoose和GraphQL的ObjectId字段的正确类型是什么?


遵循本教程,我有一个猫鼬模型:(我使用术语“account”而不是“todo”,但这是一回事)

const Account = mongoose.model('Account', new mongoose.Schema({
  id: mongoose.Schema.Types.ObjectId,
  name: String
}));

和GraphQLobJectType:

const AccountType = new GraphQLObjectType({
  name: 'account',
  fields: function () {
    return {
      id: {
        type: GraphQLID
      },
      name: {
        type: GraphQLString
      }
    }
  }
});

和一个GraphQL突变来创建其中的一个:

const mutationCreateType = new GraphQLObjectType({
  name: 'Mutation',
  fields: {
    add: {
      type: AccountType,
      description: 'Create new account',
      args: {
        name: {
          name: 'Account Name',
          type: new GraphQLNonNull(GraphQLString)
        }
      },
      resolve: (root, args) => {
        const newAccount = new Account({
          name: args.name
        });

        newAccount.id = newAccount._id;

        return new Promise((resolve, reject) => {
          newAccount.save(err => {
            if (err) reject(err);
            else resolve(newAccount);
          });
        });
      }
    }
  }
})

运行查询后:

mutation {
  add(name: "Potato")
  {
    id,
    name
  }
}

在GraphiQL中,我得到的响应是:

{
  "errors": [
    {
      "message": "ID cannot represent value: { _bsontype: \"ObjectID\", id: <Buffer 5b 94 eb ca e7 4f 2d 06 43 a6 92 20> }",
      "locations": [
        {
          "line": 33,
          "column": 5
        }
      ],
      "path": [
        "add",
        "id"
      ]
    }
  ],
  "data": {
    "add": {
      "id": null,
      "name": "Potato"
    }
  }
}

对象的创建是成功的,我可以在MongoDB Compass中看到:

但读取值似乎有问题。

graphqlidmongoose.schema.types.objectid的兼容性如何?如果它们不兼容,我是不是误解了教程,特别是它的使用:

newAccount.id = newAccount._id;

?我无法判断错误是由GraphQL,MongoDB,Mongoose还是其他东西抛出的。

编辑

有关错误的任何信息

ID不能表示值:{_bsonType:“ObjectId”,ID:}

会很有帮助的。我感觉它在告诉我它不能序列化BSON对象。但随后它将序列化显示。甚至知道什么技术(mongo?mongoose?graphql?)会有帮助。我和谷歌的关系不太好。

编辑2

这是由最近引入的graphql包的更改引起的,有一个PR正在等待merge来解决它。


共3个答案

匿名用户

我没有发现问题,就用我现有的一个代码库运行了这段代码。只是我将变异包装在GraphQLobjectType中。

const Mutation = new GraphQLObjectType({
    name: 'Mutation',
    fields: {
        addAccount: {
            type: AccountType,
            description: 'Create new account',
            args: {
                name: {
                    name: 'Account Name',
                    type: new GraphQLNonNull(GraphQLString)
                }
            },
            resolve: (root, args) => {
                const newAccount = new Account({
                    name: args.name
                });

                newAccount.id = newAccount._id;

                return new Promise((resolve, reject) => {
                    newAccount.save(err => {
                        if (err) reject(err);
                        else resolve(newAccount);
                    });
                });
            }
        }
    });

获取工作示例:克隆回购。在此回购中,应用程序使用v0.13.2,而您使用的是通过NPM i GraphQL安装的v14.0.2。将GraphQL降级到v0.13.2

匿名用户

我使用了id,它工作得很好!问题的原因不是ID的类型!这是因为您为它提供了错误的值:objectid('actuallid')

为了解决这个问题,为每个获取的数据调用ToJSON函数,或者简单地添加一个虚拟的ID,如下所示:

YourSchema.virtual('id').get(function() {
    return this.toJSON()._id
}

匿名用户

所以我刚刚发现_id的类型是objectid,但似乎隐式转换为string。因此,如果您将mongoose模型id类型定义为string,而不是mongoose.schema.types.objectid,那么它应该可以工作。使用将_id复制到id的当前代码(来自compose.com教程),结果是,在Mongo(保存后)中,_id的类型为objectid,而模型id的类型为string。

换句话说,取而代之的是

const Account = mongoose.model('Account', new mongoose.Schema({
  id: mongoose.Schema.Types.ObjectId,
  name: String
}));

这样做

const Account = mongoose.model('Account', new mongoose.Schema({
  id: String,
  name: String
}));