AddssupportforRelay-likecursorpaginationwithMongoosemodels/documents.Thislibraryalsoprovidestype-ahead(autocomplete)functionality(withpagination)usingMongoDBregularexpressionqueries.Inaddition,youcanoptionallypaginatehydratedMongoosemodelsfromElasticsearch.
Installyarnadd@limit0/mongoose-graphql-pagination
UsagePagination,type-ahead,andElastic+MongoosepaginationsupportareavailableviathePagination,TypeAheadandSearchPaginationclasses,respectively.Allclassesshouldbeconsidered,"singleuse,"andshouldbeinstantiatedonceperqueryorrequest.
PaginationReturnspaginatedresultsfromMongoDBfortheprovidedMongoosemodel.
Tobeginusing,requiretheclass
const{Pagination}=require('@limit0/mongoose-graphql-pagination');Usetheclassconstructortoconfigurethesettingsforthepaginatedquery.
constructor(Model,{criteria={},pagination={},sort={},projection},options={})Model:TheMongoosemodelinstancetoquery.Required.
criteria:Aquerycriteriaobjecttoapplytothepaginatedquery.CanbeanyMongoDBquery.Forexample:{deleted:false}or{age:{$gt:30}}.Thecriteriawillbedeeplymerged,butwillignore"special"objectssuchasObjectIdand,bydefault,willonlymerge"plainobjects."Optional.
pagination:Thepaginationparametersobject.Canacceptafirstand/orafterproperty.Thefirstvaluespecifiesthelimit/pagesize.Theaftervaluespecifiesthecursortostartatwhenpaginating.Forexample:{first:50,after:'some-cursor-value'}wouldreturnthefirst50edgesaftertheprovidedcursor.Bydefaulttheresultswillbelimitedto10edges.Optional.
sort:Specifiesthesortoptions.Thefieldpropertyspecifiesthefieldtosortby,andtheorderdefinesthedirection.Forexample:{field:'name',order:-1}wouldsorttheedgesbyname,descending.BydefaulttheedgesaresortedbyID,ascending.Optional.
projection:Specifiesthefieldstoreturnfromthedatabase.Forexample:{field:1}or{field:0}wouldincludeorexcludethespecifiedfield,respectively.Ifleftundefined,orasanemptyobject,allfieldswillbereturned(whichisthedefaultbehavior).Optional.
options:Specifiesadditionalconfigurationoptions,suchasdefaultlimit,maxlimit,sortcollation,objectmergeoptions,andsortcreatedfield.
Completeexample:
const{Pagination}=require('@limit0/mongoose-graphql-pagination');constYourModel=require('./your-model');constpaginated=newPagination(YourModel,{criteria:{deleted:false},pagination:{first:25},sort:{field:'name',order:-1},});//Retrievetheedges...constedges=paginated.getEdges();Oncetheinstanceiscreated,usethemethodslistedbelowtoaccessthepaginatedinfo.
getTotalCount()Returnsthetotalnumberofdocumentsthatmatchthequerycriteria,regardlessofpagesize(limit).
getEdges()Returnstheedges(Mongoosedocumentnodes)thatmatchthequerycriteria.Theresultswillbelimitedbythefirstvalue.
getEndCursor()Returnsthecursorvalue(non-obfuscated)ofthelastedgethatmatchesthecurrentcriteria.ThisvaluewillresolvetotheMongoosedocumentID,andcanbeconvertedintoanobfuscatedIDwhenreturnedbytheGraphQLserver.Willreturnnullifnoresultswerefound.
hasNextPage()Determinesifanotherpageofedgesisavailable,basedonthecurrentcriteria.
Type-Ahead(AutoComplete)TypeaheadsupportisimplementedusingMongoDBregularexpressionqueries.Tobeginusing,requiretheclass:
const{TypeAhead}=require('@limit0/mongoose-graphql-pagination');Usetheclassconstructortoconfigurethesettingsforthetype-aheadquery.
constructor(field,term,criteria={},options={})field:Thefieldtoquery/searchagainst.Forexample:name.Required.
term:Thesearchterm.Can/shouldbeapartialphrase.Required.
criteria:AdditionalMongoDBquerycriteriatoapplywhenquerying.Forexample{deleted:false}.Thecriteriawillbedeeplymerged,butwillignore"special"objectssuchasObjectIdand,bydefault,willonlymerge"plainobjects."Optional.
options:Thetype-aheadconfigurationoptionsobject.Hasthreetype-aheadrelatedproperties:
{//Determineshowtheregexisconstructed.//Caneitherbe`starts-with`,`ends-with`,`exact-match`or`contains`.//Defaultsto`contains`.position:'contains',//Whethertoescaperegexspecialcharacters.//Defaultsto`true`.escape:true,//Whethertotreattheregexqueryascasesensitive.//Defaultsto`false`.caseSensitive:false,}Inaddition,theoptionswillalsoaccepttheoptionalmergeOptionsobjectpropertyhtatcanbeusedtooverridethedefaultmergerules.
paginate(Model,pagination={},options={})CreatesaPaginationinstanceusingtheconstructedTypeAheadoptions.
buildCriteria()ReturnstheMongoDBcriteriathatcanbeusedforqueryingthedatabase.Generally,thiswillnotbeusedand,instead,shouldbeindirectlyaccessedviathepaginatemethod.
Completeexample:
const{TypeAhead}=require('@limit0/mongoose-graphql-pagination');constYourModel=require('./your-model');consttypeahead=newTypeAhead('name','foo',{deleted:false,},{position:'starts-with',});constpaginated=typeahead.paginate(YourModel,{first:25});//Retrievetheedges...constedges=paginated.getEdges();SearchPaginationReturnspaginatedandhydratedMongoose/MongoDBresultsfromElasticsearch.Thisassumesthatyouare,insomefashion,savingsomedataforaspecificMongoosemodelwithinElasticsearch,asthiswillattempttoconverttheElasticresultsbackintoMongoosedocumentsfromMongoDB.Thisalsoassumesthatthe_idvalueoftheindexeddocumentinElasticsearchmatchesthe_idvaluethatisstoredinMongoDB.
Tobeginusing,requiretheclass
const{SearchPagination}=require('@limit0/mongoose-graphql-pagination');Usetheclassconstructortoconfigurethesettingsforthepaginatedquery.
constructor(Model,client,{params={},pagination={}})Model:TheMongoosemodelinstancetouseforre-queryingMongoDBtohydratetheElasticsearchresults.Required.
client:TheElasticsearchclientinstancecreatedfromtheelasticsearchNode/JSAPIlibrary.Required.
params:Theelasticsearchparametersthatwillbesenttoclient.search.Forexample:{index:'some-index',type:'some-type',body:{query:{match_all:{}}}}Required.
pagination:Thepaginationparametersobject.Canacceptafirstand/orafterproperty.Thefirstvaluespecifiesthelimit/pagesize.Theaftervaluespecifiesthecursortostartatwhenpaginating.Forexample:{first:50,after:'some-cursor-value'}wouldreturnthefirst50edgesaftertheprovidedcursor.Bydefaulttheresultswillbelimitedto10edges.Optional.
Completeexample:
const{SearchPagination}=require('@limit0/mongoose-graphql-pagination');constelasticClient=require('./your-elasticsearch-client');constYourModel=require('./your-model');constparams={index:'your-index',type:'your-type',body:{query:{match_all:{}},},};constpagination={first:25};constpaginated=newSearchPagination(YourModel,elasticClient,{params,pagination});//Retrievetheedges...constedges=paginated.getEdges();Oncetheinstanceiscreated,usethemethodslistedbelowtoaccessthepaginatedinfo.
getTotalCount()Returnsthetotalnumberofdocumentsthatmatchthesearchcriteria,regardlessofpagesize(limit).
getEdges()Returnstheedges(hydratedMongoosedocumentnodesfromElasticsearchhits)thatmatchthesearchcriteria.Theresultswillbelimitedbythefirstvalue.
getEndCursor()Returnsthecursorvalue(non-obfuscated)ofthelastedgethatmatchesthecurrentcriteria.ThisvaluewillresolvetoaJSONstringifiedversionoftheElasticsearchsortvalue,andcanbeconvertedintoanobfuscatedIDwhenreturnedbytheGraphQLserver.Willreturnnullifnoresultswerefound.
hasNextPage()Determinesifanotherpageofedgesisavailable,basedonthecurrentcriteria.
PaginationResolversFinally,thepaginationResolversprovidehelperfunctionsforusingPaginationwithaGraphQLserversuchasApollo.
Forexample,ifyouhadaGraphQLdefinitionsimilartothis:
scalarCursortypeQuery{allContacts(pagination:PaginationInput={},sort:ContactSortInput={}):ContactConnection!searchContacts(pagination:PaginationInput={},phrase:String!):ContactConnection!}typeContactConnection{totalCount:Int!edges:[ContactEdge]!pageInfo:PageInfo!}typeContactEdge{node:Contact!cursor:Cursor!}typeContact{id:String!name:String!email:String!}typePageInfo{hasNextPage:Boolean!endCursor:Cursor}inputPaginationInput{first:Int!=25after:Cursor}inputContactSortInput{field:ContactSortField!=createdAtorder:Int!=-1}enumContactSortField{namecreatedAtupdatedAt}Thefollowingresolverscouldbeapplied:
const{CursorType}=require('@limit0/graphql-custom-types');const{Pagination,paginationResolvers,SearchPagination}=require('@limit0/mongoose-graphql-pagination');constelasticClient=require('./path-to/elasticsearch-client');constContact=require('./path-to/contact-model');module.exports={//Thecursortype.//WillobfuscatetheMongoIDfor`Pagination`andtheElasticsortvaluefor`SearchPagination`Cursor:CursorType,//Applythepaginationresolversfortheconnection.ContactConnection:paginationResolvers.connection,Query:{/***Usepaginationonthequery.*WillqueryMongoDBviaMongoosefortheprovidedmodel.*/allContacts:(root,{pagination,sort})=>newPagination(Contact,{pagination,sort},{//Informsthesortthatthe`createdAt`fieldspecifiesacreateddate.//WillinsteadusethedocumentIDwhensorting.sort:{createdField:'createdAt'},}),/***Usesearchpaginationonthequery.*WillqueryElasticsearchandthenhydratetheresultsfrom*MongoDB(viaMongoose)fortheprovidedmodel.*/searchContacts:(root,{pagination,phrase})=>{//Settheparametersfortheelasticclient`search`method.//@seehttps://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-searchconstparams={index:'index-where-contacts-exist',type:'type-where-contacts-exist',body:{query:{match:{name:phrase}}},};returnnewSearchPagination(Contact,elasticClient,{params,pagination});}),},};
评论