How can I use "count" and "group by" in Prisma 2? - react-apollo

I have this function which works:
export const tagsByLabel = async (params) => {
const findManyParams = {
where: { userId: userIdFromSession },
orderBy: { title: "asc" },
};
if (params) {
const { searchTerm } = params;
findManyParams.where.title = { contains: searchTerm };
}
console.log("findManyParams", findManyParams);
const tagsByLabelResult = await db.tag.findMany(findManyParams);
console.log("tagsByLabelResult", tagsByLabelResult);
return tagsByLabelResult;
};
If I search for 'mex', I see:
findManyParams {
where: { userId: 1, title: { contains: 'mex' } },
orderBy: { title: 'asc' }
}
tagsByLabelResult [
{
id: 9,
title: 'mex',
description: 'Mexican food',
userId: 1,
createdAt: 2020-05-03T22:16:09.134Z,
modifiedAt: 2020-05-03T22:16:09.134Z
}
]
And for an empty query, tagsByLabelResult contains all tag records.
How can I adjust my tagsByLabel function to aggregate (using "group by") the records and output a "count" for each record of tagsByLabelResult in order by count descending?
tagsByLabelResult [
{
id: 9,
title: 'mex',
description: 'Mexican food',
count: 25,
userId: 1,
createdAt: 2020-05-03T22:16:09.134Z,
modifiedAt: 2020-05-03T22:16:09.134Z
}
]
I see the docs example of prisma.user.count(), but that seems to retrieve a simple count of the result of the whole query rather than a count as a field with a "group by".
I'm using RedwoodJs, Prisma 2, Apollo, GraphQL.

As of now groupBy support is still in spec here so currently you would only be able to use count with specific querying.
As a workaround, you would have to use prisma.raw for the timebeing.

In my tags.sdl.js I needed to add:
type TagCount {
id: Int!
title: String!
count: Int!
principles: [Principle]
description: String
createdAt: DateTime!
modifiedAt: DateTime!
}
And change query tagsByLabel(searchTerm: String): [Tag!]! to tagsByLabel(searchTerm: String): [TagCount!]!
In my TagsAutocomplete.js component, I now have:
export const TagsAutocomplete = ({ onChange, selectedOptions, closeMenuOnSelect }) => {
const state = {
isLoading: false,
};
const client = useApolloClient();
const promiseOptions = useCallback(
async (searchTerm) => {
try {
const { data } = await client.query({
query: QUERY_TAGS_BY_LABEL,
variables: { searchTerm },
});
console.log("promiseOptions data", data);
const tags = data.tags.map((tag) => {
if (!tag.label.includes("(")) {
//ONEDAY why does the count keep getting appended if this condition isn't checked here?
tag.label = tag.label + " (" + tag.count + ")";
}
return tag;
});
console.log("promiseOptions tags", tags);
return tags;
} catch (e) {
console.error("Error fetching tags", e);
}
},
[client]
);
};
And in my tags.js service, I now have:
export const tagsByLabel = async (params) => {
let query = `
SELECT t.*, COUNT(pt.B) as count FROM tag t LEFT JOIN _PrincipleToTag pt ON t.id = pt.B WHERE t.userId = ${userIdFromSession} `;
if (params) {
const { searchTerm } = params;
if (searchTerm) {
query += `AND t.title LIKE '%${searchTerm}%' `;
}
}
query += "GROUP BY t.id ORDER BY count DESC, t.title ASC;";
console.log("query", query);
const tagsByLabelResult = await db.raw(query);
//TODO get secure parameterization working
console.log("tagsByLabelResult", tagsByLabelResult);
return tagsByLabelResult;
};
But, as mentioned in the comment, I'm still trying to figure out how to get secure parameterization working.

Related

Cast to ObjectId failed for value \"{ proposser: '618e49a68e18cd48286de4b5' }\" (type Object) at path \"_id\" for model \"Proposal\"

I am getting this error in graphql playground (image below ) .
I have checked for the validity of objectId in the resolver as well.
// model
const ProposalSchema = new Schema({
cover
Letter: {
type: String,
},
budget: {
type: String,
},
proposals: {
type: mongoose.Schema.Types.ObjectId,
},
_id: {
type: mongoose.Schema.Types.ObjectId,
},
});
//resolver
also checked If the argument is valid using mongoose.isValidObjectId(proposser) it returns true
Query: {
proposals(_, args) {
const { proposser } = args;
return Proposal.findById({
proposser,
});
},
},
// schema
const typeDefs = gql`
type Proposal {
_id: ID!
coverLetter: String
budget: String
proposser: ID!
}
`;
const Proposal = mongoose.model("Proposal", ProposalSchema);
I was using wrong method in resolvers .
findById was being used for field non Id field.
async proposals(_, args) {
const { proposser } = args;
const userProposals = await Proposal.find({
proposser,
});
try {
const result = userProposals;
return result ? result : [];
} catch (err) {
console.log(err);
}
},

todo list optimistic subscription updates with Apollo GraphQl

I am trying to get an optimistic response when I add a task to my todo list:
ADD_TASK and GET_TASK from query.ts
export const GET_TASKS = gql`
subscription {
queryTask {
id
title
completed
user {
username
}
}
}
`;
export const ADD_TASK = gql`
mutation addTask($task: AddTaskInput!) {
addTask(input: [$task]) {
task {
id
title
completed
}
}
}
`;
addTask() function
const newId = Math.round(Math.random() * -1000000);
await addTask({
variables: {
task: {
title: text,
completed: false,
user: { username: user?.email },
},
},
optimisticResponse: {
__typename: "Mutation",
addTask: {
__typename: "AddTaskPayload",
task: {
__typename: "Task",
id: newId,
title: text,
completed: false,
user: {
__typename: "User",
username: user?.email,
},
},
},
},
update(cache, { data: addTask }: any) {
const queryTask: any = cache.readQuery({
query: GET_TASKS,
});
cache.writeQuery({
query: GET_TASKS,
data: {
queryTask: [...queryTask.queryTask, addTask.addTask.task],
},
});
},
});
UPDATE
So, I got it working normally, now I just need to get it working with:
1.) Subscriptions
2.) The ID problem... it generates a random ID here instead of knowing what it should be (any suggestions)?
I am using my repository with Dgraph here.
(This does not include the optimistic version)
Any suggestions?
J

return the id of the updated document in graphql mongodb

I am new to GraphQL. I have a query which updates a user by his Id. I want to return the id of the document that was updated, but it is returning:
{
"data": {
"editUser": {
"_id": null
}
}
}
GraphQL Query:
mutation {editUser(_id: "5eb801eef0171040044de79f", name: "dd", title:"teacher" , email:"dd#here.com") {
_id
}
}
shema:
const { buildSchema } = require("graphql");
const schema = buildSchema(`type Query {
getUser(_id: ID): User
getUsers: [User]
}
type User {
_id: ID
name: String
title: String
email: String
}
type Mutation {
addUser(name: String, title: String, email: String): User,
editUser(_id: ID, name: String, title: String, email: String): User,
deleteUser(_id: ID): String
}`);
module.exports = { schema };
in resolver.js:
try {
const client = await MongoClient.connect(url);
var dbo = client.db("UserApp");
const myquery = { _id: ObjectId(args._id) };
const updateduser = await dbo
.collection("users")
.updateOne(myquery, { $set: { name: args.name } });
const founduser = await dbo.collection("users").findOne(myquery);
console.log(founduser);
return founduser._id.toString();
} catch (err) {
console.log(err);
}

Is there a way to filter json data format field in strapi?

Hi Guys I'm trying to filter post with data json format field?
"categoryList": ["cat", "cat1"]
For anyone still looking for a solution, this is what I have done for a json type field called tags of a collection type called Articles.
I have two articles in the database with one article having the following values set:
title: "lorem ipsum 1",
tags: [
"test",
"rest"
]
The other article has the following values set:
title: "lorem ipsum 2",
tags: [
"test",
"graphql"
]
My graphql query looks like this:
query {
articlesByTag(limit: 2, where: {tags_include: ["test", "rest"]}, start: 0, sort: "title:asc") {
title,
tags
}
}
While my rest query looks like this:
http://localhost:1337/articlesByTag?limit=2&tags_include[]=test&tags_include[]=rest
This is my articles.js service file:
const { convertRestQueryParams, buildQuery } = require('strapi-utils');
const _ = require('lodash');
const { convertToParams, convertToQuery } = require('../../../node_modules/strapi-plugin-graphql/services/utils');
module.exports = {
async findByTag(ctx) {
let tags_include;
if (ctx.where && ctx.where.tags_include && ctx.where.tags_include.length > 0) {
tags_include = ctx.where.tags_include;
delete ctx.where.tags_include;
} else if (ctx.query && ctx.query.tags_include && ctx.query.tags_include.length > 0) {
tags_include = ctx.query.tags_include;
delete ctx.query.tags_include;
}
if (!Array.isArray(tags_include)) {
tags_include = [tags_include];
}
let filters = null;
if (ctx.query) {
filters = convertRestQueryParams({
...convertToParams(ctx.query)
});
} else {
filters = convertRestQueryParams({
...convertToParams(_.pick(ctx, ['limit', 'start', 'sort'])),
...convertToQuery(ctx.where),
});
}
const entities = await strapi.query('articles').model.query(qb => {
buildQuery({ model: strapi.query('articles').model, filters: filters })(qb);
if (tags_include.length > 0) {
tags_include.forEach((tag) => {
if (tag && tag.length > 0) {
const likeStr = `%"${tag}"%`;
qb.andWhere('tags', 'like', likeStr);
}
});
}
}).fetchAll();
return entities;
},
};
This is the entry needed in routes.js
{
"method": "GET",
"path": "/articlesByTag",
"handler": "articles.findByTag",
"config": {
"policies": []
}
}
This is the controller articles.js
const { sanitizeEntity } = require('strapi-utils');
module.exports = {
async findByTag(ctx) {
const entities = await strapi.services.articles.findByTag(ctx);
return entities.map(entity => sanitizeEntity(entity, { model: strapi.models.articles }));
},
};
And finally this is the schema.graphql.js
module.exports = {
query: `
articlesByTag(sort: String, limit: Int, start: Int, where: JSON): [Articles]
`,
resolver: {
Query: {
articlesByTag: {
description: 'Return articles filtered by tag',
resolverOf: 'application::articles.articles.findByTag',
resolver: async (obj, options, ctx) => {
return await strapi.api.articles.controllers.articles.findByTag(options);
},
},
},
},
};
There is not currently a way to filter the JSON fields yet as of beta.17.8 (latest)
Probably something like that?
strapi.query('cool_model').find({ categoryList: { $all: [ "cat" , "cat1" ] } })

How can I select a part of a array of objects in a GraphQL query?

My resolver get
{ adminMsg:
[
{active: “y”, text1: “blah1" } ,
{active: “n”, text1: “blah2" }
] };
My query:
{
adminWarn {
adminMsg {
active, text1
}
}
}
I want only array-elements with condition: active = 'y'
I find in GQL Dokumentation no way to write this condition im my query.
Is there any solution in GQL?
Use of resolve args can solve the problem:
const adminWarnList = new GraphQLObjectType({
name: 'adminWarnReportList',
fields: () => ({
adminMsg: {
type: new GraphQLList(adminWarnFields),
},
}),
});
const adminWarn = {
type: adminWarnList,
args: {
active: { type: GraphQLString },
},
resolve: (parent, args, context) => {
...
let reportdata = context.loadData();
if (args.active == 'y') {
let filteredItems = reportdata.filter(function(item) {
return item.active != null && item.active != 'y';
});
reportdata = filteredItems;
}
return { adminMsg: reportdata };
},
};

Resources