graphql-compose-mongoose icon indicating copy to clipboard operation
graphql-compose-mongoose copied to clipboard

Features: createMany, mutation for an existing array

Open andersonlin opened this issue 8 years ago • 6 comments

hello~

Do we have plan to add createMany, and recordIds returns the array of ObjectIDs, records returns the updated objects.

//createMany
var array = [{ name: 'Star Wars' }, { name: 'The Empire Strikes Back' }];
Movies.insertMany(array, function(error, docs) {});

Could we support mutation for updating an array field if I pass an ObjectId that adding to the existing array instead of overwrite, the overwrite only happens if I pass an array of ObjectId?

The first mutation for phones and returns two values for phones being "111-222-333-444", "444-555-666-777".

mutation {
  userCreate(record: {
    contacts: {
      phones: [
        "111-222-333-444",
        "444-555-666-777"
      ]
    },
  }) {
    recordId
    record {
      contacts {
        email
        phones
      }
    }
  }
}

{
  "data": {
    "userCreate": {
      "recordId": "593ca1149f15dd003778ba1f",
      "record": {
        "contacts": {
          "email": null,
          "phones": [
            "111-222-333-444",
            "444-555-666-777"
          ]
        }
      }
    }
  }
}

The second mutation for phones, the expected returns are three values for phones being "111-222-333-444", "444-555-666-777", "444-555-666-888" instead of "444-555-666-888".

mutation {
  userCreate(record: {
    contacts: {
      phones: "444-555-666-888"
    },
  }) {
    recordId
    record {
      contacts {
        email
        phones
      }
    }
  }
}

{
  "data": {
    "userCreate": {
      "recordId": "593ca1149f15dd003778ba1f",
      "record": {
        "contacts": {
          "email": null,
          "phones": [
            "111-222-333-444",
            "444-555-666-777",
            "444-555-666-888"
          ]
        }
      }
    }
  }
}

thanks, anderson

andersonlin avatar Jun 11 '17 01:06 andersonlin

createMany resolver make sense. Can you make PR? Just copy https://github.com/nodkz/graphql-compose-mongoose/blob/master/src/resolvers/createOne.js and its tests and make situable changes. It will be awesome.

About pushing value to array I need to think a little bit more. Cause when we create such resolver, somebody else wants to pop resolver and bunch of others. And with time this lib becomes fat. Anyway you may create custom resolvers in TC to get it working right now in your code:

UserTC = myCustomHelper(composeWithMongoose(UserModel));

function myCustomHelper(tc) {
  tc.setResolver('pushToArray', new Resolver(...));
  tc.setResolver('somethingElse', ...);
  return tc;
}

Write your helpers and compose types 😉 If you write such helpers fill free to share it with me for review, maybe some parts goes to docs.

nodkz avatar Jun 15 '17 03:06 nodkz

Or such

UserTC = extendedComposeWithMongoose(UserModel);

Function extendedComposeWithMongoose(mongooseModel) {
  const tc = composeWithMongoose(mongooseModel);
  tc...
  return tc;
}

nodkz avatar Jun 15 '17 03:06 nodkz

In case this is useful for anybody from the future I implemented such a resolver:-

MessageTC.addResolver({
	name: 'pushToArray',
	type: MessageTC,
	args: { id: 'MongoID!', readBy: '[MongoID]' },
	resolve: async ({ source, args, context, info }) => { // only used args but keeping for clarity
		const message = await Message.update({ _id: args.id }, { $addToSet: { readBy: { $each: args.readBy } } })
		if (!message) return null
		return Message.findOne({ _id: args.id })
	}
})

This takes an id to update and an array of MongoIDs to add to an existing field 'readBy'. I use $addToSet which will add unique elements to the array only. If you don't care about duplicates use $push instead.

Don't forget to .addFields({myField: MessageTC.getResolver('pushToArray')})

@nodkz might be worth mentioning this approach in the docs as I expect it is a fairly common use case and I spent a few hours before reaching this thread and the above solution

Also what's the difference between addResolver and setResolver I wasn't clear from the docs. Thank you.

mattslight avatar Aug 16 '18 15:08 mattslight

@mattslight feel free to open PR and add this in README's FAQ 🙏


About difference in methods:

  • addResolver(opts)- use under the hood setResolver method; opts can be a Resolver object or options for resolver creation { name: , kind: , resolve: , args: , ... }. This methods create resolver if needed, takes its name and pass to .setResolver(resolver.name, resolver).

  • setResolver(name: string, resolver: Resolver) add resolver with provided name, which may differ from internal Resolver name

eg.

const r = Resolver({ name: 'findMany', ... });
UserTC.setResolver('fm', r); // will add resolver under name `fm`
UserTC.addResolver(r); // will add resolver under original name `findMany`

Very hidden but usefull difference.

nodkz avatar Aug 16 '18 16:08 nodkz

@nodkz FAQ updated and PR sent, I tidied the example up and I didn't use your function wrapper example as per below, as I figured that even though it is more reusable it is a slightly more advanced approach.

UserTC = myCustomHelper(composeWithMongoose(UserModel));

function myCustomHelper(tc) {
  tc.setResolver('pushToArray', new Resolver(...));
  tc.setResolver('somethingElse', ...);
  return tc;
}

mattslight avatar Aug 16 '18 21:08 mattslight

@mattslight yep, I'm widely using similar helpers like myCustomHelper in my App when I need a reusble specific logic in many types. Exactly for such things was designed graphql-compose.

nodkz avatar Aug 17 '18 05:08 nodkz