Reputation: 67
This is a GraphQL resolver. The problem is with promise handling using async/await.
I have tried to implement promise handling, but I am not able to set it the right way, I do not have much experience in promise handling, some study materials will do a great help.
My understanding was that the script will stop where await is called and will continue after the await call is finished. but it is bypassing the await. await call is finished after the value is returned
allDocs: async (args, context) => context().then(async client => {
let db = client.db(dbName)
const id = args.identifier.trim()
let nameArr = []
return await db.collection("collection").find({
$or: [{
"a.iden": id
}, {
"b.iden": id
}]
}).toArray().then(async (arr) => {
let year
arr.map(async element => {
let pmcid = element.pmc_id.toUpperCase()
try {
year = await db.collection("Another_collection").findOne({"pmcid" : query})["year"]
} catch (e) {
year = null
}
element["publication_year"] = year
})
return await arr
}).then((arr)=>{
client.close()
return {
"documents": arr,
"count": arr.length,
"searchkey": id
}
})
}),
The expected return value should have "publication_year" as some year, it is giving null now.
Thanks for help
Upvotes: 2
Views: 238
Reputation: 103305
You seem to mixing Promises with async/await and it's a bit hard to follow. Always better to break down your code by changing the Promise bits to use async/await as this will help you narrow down the issue. You can as well wrap the whole block in a try/catch which makes it relatively easy to handle both synchronous and asynchronous errors.
So to begin with, you can change the context function call which returns a promise to use async await as
allDocs: async (args, context) => {
try {
const client = await context()
....
} catch(err) {
}
}
Then do the same with the toArray()
function call which returns a promise that can be resolved with async/await:
allDocs: async (args, context) => {
try {
const client = await context()
const db = client.db(dbName)
const id = args.identifier.trim()
const results = await db.collection('collection').find({
'$or': [
{ 'a.iden': id },
{ 'b.iden': id }
]
}).toArray()
const arr = results.map(async doc => {
const pmcid = doc.pmc_id.toUpperCase()
const { year } = await db.collection('Another_collection')
.findOne({'pmcid' : pmcid })
return {
...doc,
publication_year: year
}
})
client.close()
return {
'documents': arr,
'count': arr.length,
'searchkey': id
}
} catch(err) {
// handle error
}
}
The call to the other collection to get the publication_year
can be done using a $lookup
pipeline in a single call rather than in a map loop. Consider the following pipeline
allDocs: async (args, context) => {
try {
const client = await context()
const db = client.db(dbName)
const id = args.identifier.trim()
const pipeline = [
{ '$match': {
'$or': [
{ 'a.iden': id },
{ 'b.iden': id }
]
} },
{ '$lookup': {
'from': 'Another_collection',
'let': { 'pmcId': '$pmc_id' },
'pipeline': [
{ '$match': {
'$expr': {
'$eq': [
'$pmcid',
{ '$toUpper': '$$pmcId' }
]
}
} }
],
'as': 'pmc'
} },
{ '$addFields': {
'publication_year': {
'$arrayElemAt': [ '$pmc.year', 0 ]
}
} },
{ '$project': { 'pmc': 0 } }
]
const arr = await db.collection('collection').aggregate(pipeline).toArray()
client.close()
return {
'documents': arr,
'count': arr.length,
'searchkey': id
}
} catch(err) {
// handle error
}
}
Upvotes: 1