Order result resolved via resolver in graphql + apollo server + nodejs - node.js

I am trying to order an array returned by resolver in GraphQL.
I can only think of way of ordering data using DB Query, but how can we order data that GraphQL resolves using its resolver functions?
Below is my Query resolver:
getAllNotifications: (
_parent,
_args: { authorId: string },
context: Context
) => {
return context.prisma.blog.findMany({
where: {
authorId: _args.authorId,
},
orderBy: {
created_at: "desc",
},
});
},
And my query:
query Query($authorId: String) {
getAllNotifications(authorId: $authorId) {
title
comment {
id
created_at
}
}
}
And result:
{
"data": {
"getAllNotifications": [
{
"title": "First Ride! ",
"comment": [ <--- I am trying to order this comment array using created_at date
{
"id": "cl8afqaqx001209jtxx7mt5h6",
"created_at": "2022-09-20T16:53:07.689Z"
},
{
"id": "cl8agiq71001509l27or7oxyd",
"created_at": "2022-09-20T17:15:14.077Z"
},
{
"id": "cl8ahmvrm003109l8dp684bn6",
"created_at": "2022-09-20T17:46:27.538Z"
},
{
"id": "cl99kj24p002609iajdbpycg0",
"created_at": "2022-10-15T06:59:24.169Z"
}
]
}
]
}
}
I didn't found anything in Graphql docs regarding ordering data returned by resolver

GraphQL doesn't have functions for selection and ordering, those are jobs that resolvers must do.
Add a resolver for comment that sorts the comment array. Your existing sort just sorts based on the created_at date of the post.

Related

Conditionally adding term and multi_match filters to elasticsearch with nodejs client

I am using ElasticSearch 7.9 with a nodejs client. I have the following query :
{
"query": {
"bool": {
"must":[
{ "terms" : { "id" : ["5f0d06fb5112231eb89eb819", "5f0d06fb5112231eb89eb817"] } },
{"query_string": {
"query": "(News) OR (Entertainent)",
"fields": [ "topics", "subTopics", "categories"]
}
},
{
"multi_match": {
"query": "publisher",
"fields": ["text", "name", "title", "subtitle", "description"]
}
}
]
}
}
}
I want to be able to conditionally add the terms filter for id if list of ids coming in to the nodejs/js function is not empty. Similarly for the multi_match query text as well. Add the multi_filter only if the incoming text is not empty
Should all queries be pre-constructed or is it possible to have conditional blocks and add only if the empty text or array of Ids are not empty.
My current method expects both ids and text input to the method to have valid values but these could be empty. Do I separate methods to handle the empty conditions
export const searchResults = async (text, ids) => {
const response = await client.search({
index: "new_index", //customer.id
type: "_doc",
body: {
query: {
bool: {
must: [
{terms: {"id": ids}},
{query_string: {
query: "(News) OR (Entertainent)",
fields: [ "topics", "subTopics", "categories"]
}
},
{
multi_match: {
query: text,
fields: ["text", "name", "title", "subtitle", "description"],
}
}
],
}
}
},
});
return response?.hits?.hits.map(({_source}) => _source) || [];
};
any help is really appreciated.
In a production environment and managing client based applications you should use search-templates, where you can use conditional blocks of queries. Besides, if you would want to change your query you would not neet to redeploy your app, just change it on ES.

Query Postgres Nested JSONB column using sequelize

Hi I have a table where I use JSONB to store Nested JSON data and need to query this JSONB column
Below is the structure of the table
{
"id": "5810f6b3-fefb-4eb1-befc-7df11a24d997",
"entity": "LocationTypes",
"event_name": "LocationTypes added",
"data": {
"event":{
"id": "b2805163-78f0-4384-bad6-1df8d35b456d",
"name": "builidng",
"company_id": "1dd83f77-fdf1-496d-9e0b-f502788c3a7b",
"is_address_applicable": true,
"is_location_map_applicable": true}
},
"notes": null,
"event_time": "2020-11-05T10:56:34.909Z",
"company_id": "1dd83f77-fdf1-496d-9e0b-f502788c3a7b",
"created_at": "2020-11-05T10:56:34.909Z",
"updated_at": "2020-11-05T10:56:34.909Z"
}
The code below is giving blank array as response
const dataJson = await database.activity_logs.findAll({
where: {
'data.event.id': {
$eq: 'b2805163-78f0-4384-bad6-1df8d35b456d',
},
},
raw: true,
});
Is there any way I can accomplish querying nested json object using sequelize in a better way .
You should try sequelize.literal with JSON-operators/functions wrapped into sequelize.where. Something like this:
sequelize.where(sequelize.literal("data->'event'->'id'"), '=', 'b2805163-78f0-4384-bad6-1df8d35b456d')
more recent syntax (not sure from what Sequelize version it starts to work) to construct conditions against JSON:
{
data: {
event: {
id: 'b2805163-78f0-4384-bad6-1df8d35b456d'
}
}
}

Not able to query for nested relations using dgraph-orm

I am using dgraph-orm for fetching nested relational values but it works for single level but not multiple level.
I am getting the page details but unable to fetch the avatar of the page.
Here is my snippet:
let posts = await PagePost.has('page_id', {
filter: {
page_id: {
uid_in: [page_id]
}
},
include: {
page_id: {
as: 'page',
include: {
avatar: {
as: 'avatar'
}
}
},
owner_id: {
as: 'postedBy'
}
},
order: [], // accepts order like the above example
first: perPage, // accepts first
offset: offset, // accepts offset
});
I am not getting avatar for the attribute page_id:
{
"uid": "0x75b4",
"title": "",
"content": "haha",
"created_at": "2019-09-23T08:50:52.957Z",
"status": true,
"page": [
{
"uid": "0x75ac",
"name": "Saregamaapaaaa...",
"description": "This a is place where you can listen ti thrilling music.",
"created_at": "2019-09-23T06:46:50.756Z",
"status": true
}
],
"postedBy": [
{
"uid": "0x3",
"first_name": "Mohit",
"last_name": "Talwar",
"created_at": "2019-07-11T11:37:33.853Z",
"status": true
}
]
}
Is there a support for multilevel field querying in the orm??
There was some issue with ORM itself it was not able to recognize the correct model name for multilevel includes and generating the wrong queries.
Fixed the same in version 1.2.4, please run npm update dgraph-orm --save to update your DgraphORM.
Thanks for the issue.

MongoDB: Query model and check if document contains object or not, then mark / group result

I have a Model called Post, witch contains an property array with user-ids for users that have liked this post.
Now, i need to query the post model, and mark the returned results with likedBySelf true/false for use in by client - is this possible?
I dont have to store the likedBySelf property in the database, just modify the results to have that property.
A temporary solution i found was to do 2 queries, one that finds the posts that is liked by user x, and the ones that have not been liked by user x, and en map (setting likedBySelf true/false) and combine the 2 arrays and return the combined array. But this gives some limitations to other query functions such as limit and skip.
So now my queries looks like this:
var notLikedByQuery = Post.find({likedBy: {$ne: req.body.user._id}})
var likedByQuery = Post.find({likedBy: req.body.user._id})
(I'm using the Mongoose lib)
PS. A typical post can look like this (JSON):
{
"_id": {
"$oid": "55fc463c83b2d2501f563544"
},
"__t": "Post",
"groupId": {
"$oid": "55fc463c83b2d2501f563545"
},
"inactiveAfter": {
"$date": "2015-09-25T17:13:32.426Z"
},
"imageUrl": "https://hootappprodstorage.blob.core.windows.net/devphotos/55fc463b83b2d2501f563543.jpeg",
"createdBy": {
"$oid": "55c49e2d40b3b5b80cbe9a03"
},
"inactive": false,
"recentComments": [],
"likes": 8,
"likedBy": [
{
"$oid": "558b2ce70553f7e807f636c7"
},
{
"$oid": "559e8573ed7c830c0a677c36"
},
{
"$oid": "559e85bced7c830c0a677c43"
},
{
"$oid": "559e854bed7c830c0a677c32"
},
{
"$oid": "559e85abed7c830c0a677c40"
},
{
"$oid": "55911104be2f86e81d0fb573"
},
{
"$oid": "559e858fed7c830c0a677c3b"
},
{
"$oid": "559e8586ed7c830c0a677c3a"
}
],
"location": {
"type": "Point",
"coordinates": [
10.01941398718396,
60.96738099591897
]
},
"updatedAt": {
"$date": "2015-09-22T08:45:41.480Z"
},
"createdAt": {
"$date": "2015-09-18T17:13:32.426Z"
},
"__v": 8
}
#tskippe you can use a method like following to process whether the post is liked by the user himself and call the function anywhere you want.
var processIsLiked = function(postId, userId, doc, next){
var q = Post.find({post_id: postId});
q.lean().exec(function(err,res){
if(err) return utils.handleErr(err, res);
else {
if(_.find(doc.post.likedBy,userId)){ //if LikedBy array contains the user
doc.post.isLiked = true;
} else {
doc.post.isLiked = false;
}
});
next(doc);
}
});
}
Because you are using q.lean() you dont need to actually persist the data. You need to just process it , add isLiked field in the post and send back the response. **note that we are manuplating doc directly. Also you chan tweek it to accept doc containing array of posts and iterating it and attach an isLiked field to each post.
I found that MongoDB's aggregation with $project tequnique was my best bet. So i wrote up an aggregation like this.
Explanation:
Since i want to keep the entire document, but $project purpose is to modify the docs, thus you have to specify the properties you want to keep. A simple way of keeping all the properties is to use "$$ROOT".
So i define a $project, set all my original properties to doc: "$$ROOT", then create a new property "likedBySelf", which is marked true / false if a specified USERID is in the $likedBy set.
I think that this is more clean and simple, than querying every single model after a query to set a likedBySelf flag. It may not be faster, but its cleaner.
Model.aggregate([
{ $project: {
doc: "$$ROOT",
likedBySelf: {
$cond: {
"if": { "$setIsSubset": [
[USERID],
"$likedBy"
]},
"then": true,
"else": false
}
}
}}
]);

mongodb update push array

I have the following schema. I am using node.js with mongodb
attributes: {
type: { type: 'string' },
title: { type:'string' },
description: { type:'string' },
is_active: { type:'boolean',defaultsTo:true },
createdBy: { type:'json' },
attachments:{ type:'array' }
}
arr = [{
'id':attResult.id,
'subtype':type,
'title' : attResult.title,
'body' : attResult.body,
'filetype' : attResult.filetype
}];
I am trying to push a attachments into the 'attachments' array that will be unique to the document.
This is the my query.
books.update(
{ id: refid },
{ $push: { attachments: arr } }
).done(function (err, updElem) {
console.log("updElem" + JSON.stringify(updElem));
});
What is the problem in my query,no error but not updated attachments.
I want my result to be this:
{
"_id" : 5,
"attachments": [
{
"id": "xxxxxxx",
"subtype": "book",
"title": "xxxx",
"body": "xxxx" ,
"filetype" : "xxxxx"
},
{
"id": "xxxxxxx",
"subtype": "book",
"title": "xxxx",
"body": "xxxx",
"filetype": "xxxxx"
}
]
}
Someone who trying to push the element into an array is possible now, using the native mongodb library.
Considering the following mongodb collection object
{
"_id" : 5,
"attachments": [
{
"id": "xxxxxxx",
"subtype": "book",
"title": "xxxx",
"body": "xxxx" ,
"filetype" : "xxxxx"
},
{
"id": "xxxxxxx",
"subtype": "book",
"title": "xxxx",
"body": "xxxx",
"filetype": "xxxxx"
}
]
}
arr = [{
'id':'123456',
'subtype':'book',
'title' : 'c programing',
'body' :' complete tutorial for c',
'filetype' : '.pdf'
},
{
'id':'123457',
'subtype':'book',
'title' : 'Java programing',
'body' :' complete tutorial for Java',
'filetype' : '.pdf'
}
];
The following query can be used to push the array element to "attachments" at the end. $push or $addToSet can be used for this.
This will be inserting one object or element into attachments
db.collection('books').updateOne(
{ "_id": refid }, // query matching , refId should be "ObjectId" type
{ $push: { "attachments": arr[0] } } //single object will be pushed to attachemnts
).done(function (err, updElem) {
console.log("updElem" + JSON.stringify(updElem));
});
This will be inserting each object in the array into attachments
db.collection('books').updateOne(
{ "_id": refid }, // query matching , refId should be "ObjectId" type
{ $push: { "attachments":{$each: arr} } } // arr will be array of objects
).done(function (err, updElem) {
console.log("updElem" + JSON.stringify(updElem));
});
Looking at your question a little bit more I'm betting that you are actually using "sails" here even though your question is not tagged as such.
The issue here is that the waterline ODM/ORM has it's own ideas about what sort of operations are actually supported since it tries to be agnostic between working with SQL/NoSQL backends and sort of demands a certain may of doing things.
The result is that updates with $push are not really supported at present and you need more of a JavaScript manipulation affair. So in fact you need to manipulate this via a .findOne and .save() operation:
books.findOne(refid).exec(function(err,book) {
book.attachments.push( arr[0] );
book.save(function(err){
// something here
});
});
Part of that is "waterline" shorthand for what would otherwise be considered an interchangeable use of _id and id as terms, where just specifying the id value as a single argument implies that you are referring to the id value in your query selection.
So unless you replace the waterline ODM/ORM you are pretty much stuck with this AFAIK until there is a decision to maintain this logic in a way that is more consistent with the MongoDB API or otherwise allow access to the "raw" driver interface to perform these .update() operations.
For reference though, and has been alluded to, your general "shell" syntax or what would otherwise be supported in MongoDB specific drivers is like this with the deprecation of the $pushAll operator and the intention being to merge the functionality with the $push and $addToSet operators using the $each modifier:
db.collection.update(
{ "_id": ObjectId(refid) }, // should be important to "cast"
{
"$push": {
"attachments": {
"$each": arr
}
}
}
)
So that syntax would work where it applies, but for you I am thinking that in "sails" it will not.
That gives you some food for thought, and some insight into the correct way to do things.
You are trying to insert an array as an element into your array. You may want to look at $pushAll as a short term solution. This operator is deprecated however see here.
Alternatively you can simply iterate over your array, and each iteration push an element from your array into attachments (this is the recommended approach by Mongo devs).

Resources