Linking collections in GraphQL resolver - node.js

I am trying to join two collections in GraphQL query.
My data is as follows:
Cruises:
[
{
"cruiseID" : "00001",
"title" : "title 1",
"description" : "desc 1",
"startDate" : 20150820,
"endDate" : 20150827,
"numDays" : 8,
"startPort" : "Juneau, Alaska",
"roomTypes" : [
{"roomID" : "IPD"},
{"roomID" : "SDS"}
]
}, {
"cruiseID" : "00002",
"title" : "title 1",
"description" : "desc 2",
"startDate" : 20150710,
"endDate" : 20150724,
"numDays" : 14,
"startPort" : "San Diego",
"roomTypes" : [
{"roomID" : "IPD"},
{"roomID" : "SJS"},
{"roomID" : "SDS"}
]
}
]
Rooms:
[
{
"roomID": "IPD",
"roomDetails": {
"roomType": "IPD aaaaa",
"title": "aaaa",
"description": "ddddd",
"maxOccupants": 2
},
"capacity": [
{"cruiseID": "00001", "total": 21, "available": 20},
{"cruiseID": "00002", "total": 31, "available": 30}
]
},
{
"roomID": "SJS",
"roomDetails": {
"roomType": "SJS aaaa",
"title": "aaaaa",
"description": "aaaaa",
"maxOccupants": 4
},
"capacity": [
{"cruiseID": "00001", "available": 27},
{"cruiseID": "00002", "available": 27}
]
},
{
"roomID": "SDS",
"roomDetails": {
"roomType": "SDS aaa",
"title": "sssss",
"description": "sssssss",
"maxOccupants": 4
},
"capacity": [
{"cruiseID": "00001", "available": 20},
{"cruiseID": "00002", "available": 20}
]
}
]
My GraphQL schema:
type Query {
Cruises: [Cruise]
}
type RoomDetails {
roomType: String
title: String
description: String
maxOccupants: Int
}
type Capacity {
cruiseID: String
total: Int
available: Int
}
type Room {
roomID: String
roomDetails: RoomDetails
capacity: [Capacity]
}
type Cruise {
_id: ID
cruiseID: String
title: String
description: String
startDate: Int
endDate: Int
numDays: Int
startPort: String
roomTypes: [Room]
}
My GraphQL resolver where I try to print details for roomTypes by reading them from rooms collection:
const Query = {
Cruises: async () => {
data = await db.collection('cruises').find().toArray().then(res => { return res });
return data
}
}
const Cruise = {
roomTypes: async (root) => {
data = await db.collection('rooms').find({'roomID': 'SDS'}).toArray().then(res => { return res });
// prints OK
logger.debug(`root.roomTypes.roomID': ${JSON.stringify(root.roomTypes[1].roomID)}`);
// undefined
logger.debug(`root.roomTypes.roomID': ${JSON.stringify(root.roomTypes.roomID)}`);
// prints OK
logger.debug(`root.startPort': ${root.startPort}`);
return data
}
}
module.exports = {
Query,
Cruise
}
I can't find a proper join between Cruises and Rooms.
Hardcoded {'roomID': 'SDS'} works OK i.e. shows proper output.
However, I can't find a way to properly pass roomID from Cruises to the find filter. Any hints?
UPDATE:
When I implement the resolver life this:
const Cruise = {
roomTypes: async (root) => {
data = await db.collection('rooms').find({'capacity.cruiseID': root.cruiseID}).toArray().then(res => { return res })
//data = await db.collection('rooms').find().toArray().then(res => { return res })
return data
}
}
I get the data back (roomTypes fully resolved) but, it doesn't do any filtering/joining actually.
Here's what I get (edited with some rubbish data so it's shorter):
"data": {
"Cruises": [
{
"cruiseID": "00001",
"title": "and",
"startDate": 20150820,
"endDate": 20150827,
"numDays": 8,
"startPort": "Juneau, Alaska",
"roomTypes": [
{
"roomID": "IPD",
"roomDetails": {
"roomType": "asd",
"title": "and",
"description": "asdr",
"maxOccupants": 2
},
"capacity": [
{
"cruiseID": "00001",
"total": 21,
"available": 20
},
{
"cruiseID": "00002",
"total": 31,
"available": 30
}
]
},
{
"roomID": "OPD",
"roomDetails": {
"roomType": "ad",
"title": "and",
"description": "asdr",
"maxOccupants": 2
},
"capacity": [
{
"cruiseID": "00001",
"total": null,
"available": 30
},
{
"cruiseID": "00002",
"total": null,
"available": 30
}
]
},
{
"roomID": "SDD",
"roomDetails": {
"roomType": "asd",
"title": "and",
"description": "and",
"maxOccupants": 2
},
"capacity": [
{
"cruiseID": "00001",
"total": null,
"available": 25
},
{
"cruiseID": "00002",
"total": null,
"available": 25
}
]
},
{
"roomID": "SD2",
"roomDetails": {
"roomType": "asd",
"title": "and",
"description": "Fast",
"maxOccupants": 4
},
"capacity": [
{
"cruiseID": "00001",
"total": null,
"available": 22
},
{
"cruiseID": "00002",
"total": null,
"available": 22
}
]
},
{
"roomID": "SJS",
"roomDetails": {
"roomType": "asd",
"title": "and",
"description": "Tasdr",
"maxOccupants": 4
},
"capacity": [
{
"cruiseID": "00001",
"total": null,
"available": 27
},
{
"cruiseID": "00002",
"total": null,
"available": 27
}
]
},
{
"roomID": "SDS",
"roomDetails": {
"roomType": "asd",
"title": "and",
"description": "Tase",
"maxOccupants": 4
},
"capacity": [
{
"cruiseID": "00001",
"total": null,
"available": 20
},
{
"cruiseID": "00002",
"total": null,
"available": 20
}
]
}
]
},
instead of only having 2 room types (IPD, SDS) listed for cruiseID 00001 as per the entries in Cruises collection.

This is how I finally did it. It's not the cleanest code/solution but it does the job.
const Cruise = {
roomTypes: async (root) => {
let rooms = root.roomTypes;
allRooms = await db.collection('rooms').find().toArray().then(res => { return res });
rooms.forEach(room => {
let currentRoomID = room.roomID;
currentRoom = allRooms.filter(function(r) {
return r.roomID === currentRoomID;
});
currentRoomCapacity = currentRoom[0].capacity.filter(function(c) {
return c.cruiseID === root.cruiseID;
});
room.roomDetails = currentRoom[0].roomDetails
room.capacity = currentRoomCapacity
});
return rooms;
}
}

Related

mongodb update value in 3 level nested array of objects

I want to update flag in array of objects which are 3 levels deep nested.
I have this array of ages:
[20, 25]
I want to set flag: 1 for those users which has type: students and ages: 20 or 25
Here is my Users collection:
{
"_id": "wef324DGSshf",
"userTypes": [
{
"type": "students",
"users": [
{
"name": "John",
"age": 20,
"flag": 0
},
{
"name": "Mike",
"age": 25,
"flag": 0
}
]
},
{
"type": "students",
"users": [
{
"name": "Henry",
"age": 40,
"flag": 0
},
{
"name": "Nick",
"age": 25,
"flag": 0
}
]
},
{
"type": "teachers",
"users": [
{
"name": "Kim",
"age": 20,
"flag": 0
},
{
"name": "Charles",
"age": 25,
"flag": 0
}
]
}
]
}
After update I expect this response:
{
"_id": "wef324DGSshf",
"userTypes": [
{
"type": "students",
"users": [
{
"name": "John",
"age": 20,
"flag": 1
},
{
"name": "Mike",
"age": 25,
"flag": 1
}
]
},
{
"type": "students",
"users": [
{
"name": "Henry",
"age": 40,
"flag": 0
},
{
"name": "Nick",
"age": 25,
"flag": 1
}
]
},
{
"type": "teachers",
"users": [
{
"name": "Kim",
"age": 20,
"flag": 0
},
{
"name": "Charles",
"age": 25,
"flag": 0
}
]
}
]
}
What I have tried so far is this query:
Users.update(
{ "userTypes.users.age": { $in: [20,25] } },
{ "$set": { "userTypes.users.$.flag": "1" } }
);
My solution is not updating the desired records, can anyone help me with the right query for this case?

How can I mutate the json in the following way in javascript

I have been asked in an interview to mutate the array of objects in such a way that the data appears in the following manner
[
{
"companyName": "ABC",
"members": [
{
"id": 13121212,
"firstName": "Ray",
"lastName": "Fernandis",
"points": 1800,
"position": 1
},
{
"id": 13131313,
"firstName": "Carrie",
"lastName": "Yoda",
"points": 1200,
"position": 2
}
]
}]
and the sample data was given below.
[
{
"communityName": "ABC",
"lastUpdateTimestamp": {
"date": {
"year": 2020,
"month": 10,
"day": 7
},
"time": {
"hour": 18,
"minute": 6,
"second": 5,
"nano": 536529000
}
},
"data": {
"listChannelsData": [
{
"channelId": 1234,
"channelName": "BCD",
"members": [
{
"id": 13121212,
"firstName": "Ray",
"lastName": "Fernandis",
"points": 1800,
"position": 1
}
]
}
]
}
},
{
"communityName": "DEF",
"lastUpdateTimestamp": {
"date": {
"year": 2020,
"month": 10,
"day": 7
},
"time": {
"hour": 18,
"minute": 6,
"second": 21,
"nano": 47894000
}
},
"data": {
"listChannelsData": [
{
"channelId": 3421,
"channelName": "GHI",
"members": [
{
"id": 13121212,
"firstName": "Nicholas",
"lastName": "Xin",
"points": 800,
"position": 2
},
{
"id": 13131313,
"firstName": "Carrie",
"lastName": "Yoda",
"points": 1000,
"position": 1
}
]
}
]
}
}
]
The agenda for me was to print the derived json from sample json and I could only figure out this much code which was a courtesy of stackoverflow
function dictionary(data) {
var map = {};
data.forEach(item => {
if (!Array.isArray(map[item.companyName])) {
map[item.companyName] = [item.data.listChannelsData];
} else {
map[item.communityName].push(item.data.listChannelsData);
}
});
return map;
}
console.log(dictionary(data));
But now when I try to pick up the data for the member using another foreach loop, I'm not able to access the data for members. Can anyone help me with the part where I can successfully access the member array and print the company name along side it
Try this code
var newArray = []
data.map((item, index) => {
newArray[index] = {companyName : item.communityName}
newArray[index].members = item.data.listChannelsData[0].members
})
data is the given data.

How to filter child array data in mongodb collection?

The following code joins 'cruises' and 'rooms' collections.
dbo.collection('cruises').aggregate([
{ $lookup: {from: 'rooms', localField: 'roomTypes.roomID', foreignField: 'roomID', as: 'roomTypes'} },
{
$project: {
_id: 0,
'roomTypes': {
_id: 0
}
}
}
]).toArray(function(err, data) {
if (err) {
logger.error(`getCruises : Error reading cruises db`);
logger.error(` Error: ${err}`);
callback(err, null);
} else {
let cruisesData = data;
callback(null, cruisesData);
}
});
to produce the following output. The roomTypes comes from 'rooms' collection.
[
{
"cruiseID": "00001",
"title": "some title",
"description": "some desc"
"roomTypes": [
{
"roomID": "IPD",
"roomDetails": {
"roomType": "some type",
"title": "some title",
"description": "desc",
"maxOccupants": 2
},
"capacity": [
{
"cruiseID": "00001",
"available": 20
},{
"cruiseID": "00002",
"available": 10
}
]
},
{
"cruiseID": "00002",
"title": "some other title",
"description": "some other desc"
"roomTypes": [
{
"roomID": "IPD",
"roomDetails": {
"roomType": "some type",
"title": "some title",
"description": "desc",
"maxOccupants": 2
},
"capacity": [
{
"cruiseID": "00001",
"available": 20
},{
"cruiseID": "00002",
"available": 10
}
]
}
]
How do I change it to get the following output. I.e. to show the capacity for the matching cruiseID. If it would be easier to achieve it with changed data model, feel free to suggest it as well.
[
{
"cruiseID": "00001",
"title": "some title",
"description": "some desc"
"roomTypes": [
{
"roomID": "IPD",
"roomDetails": {
"roomType": "some type",
"title": "some title",
"description": "desc",
"maxOccupants": 2
},
"capacity": 20
},
{
"cruiseID": "00002",
"title": "some other title",
"description": "some other desc"
"roomTypes": [
{
"roomID": "IPD",
"roomDetails": {
"roomType": "some type",
"title": "some title",
"description": "desc",
"maxOccupants": 2
},
"capacity": 10
}
]
You can use a extra pipeline stage at the end of your pipeline stages,
$map to iterate loop of roomTypes array
$reduce to check condition if cruiseID match then return available
$mergeObjects with current object of roomTypes and return document
// <= skipping your pipeline stages
{
$addFields: {
roomTypes: {
$map: {
input: "$roomTypes",
in: {
$mergeObjects: [
"$$this",
{
capacity: {
$reduce: {
input: "$$this.capacity",
initialValue: 0,
in: {
$cond: [
{ $eq: ["$$this.cruiseID", "$cruiseID"] },
"$$this.available",
"$$value"
]
}
}
}
}
]
}
}
}
}
}
Playground
Second possible way you can do this,
Playground
You could do a simple array mapping.
Note:
This is just a workaround, you could probably improve your schema or
query or something.
Here's the code. Basically just map the nested capacity property of each cruise and use find method to find the matching capacity and pluck the available property.
var data = [{
"cruiseID": "00001",
"title": "some title",
"description": "some desc",
"roomTypes": [{
"roomID": "IPD",
"roomDetails": {
"roomType": "some type",
"title": "some title",
"description": "desc",
"maxOccupants": 2
},
"capacity": [{
"cruiseID": "00001",
"available": 20
}, {
"cruiseID": "00002",
"available": 10
}]
}]
},
{
"cruiseID": "00002",
"title": "some other title",
"description": "some other desc",
"roomTypes": [{
"roomID": "IPD",
"roomDetails": {
"roomType": "some type",
"title": "some title",
"description": "desc",
"maxOccupants": 2
},
"capacity": [{
"cruiseID": "00001",
"available": 20
}, {
"cruiseID": "00002",
"available": 10
}]
}]
}
]
var test = data.map(cruise => {
return {
...cruise,
roomTypes: cruise.roomTypes.map(room => {
return {
...room,
capacity: room.capacity.find(c => c.cruiseID === cruise.cruiseID).available
}
})
}
});
console.log(test);

Issue with to get data from MongoDB aggregate

I want data from places where userid is equal to the body.user._id
PLACE DATA
{
"_id": "5e8ddd0f7f5b174290bbefc8",
"type": 0,
"location": [
24.8757396,
67.3464698
],
"title": "E 22, Steel Town Karachi, Karachi City, Sindh, Pakistan",
"googlePlaceId": "ChIJlbvA8BIzsz4Rlh7w_fKfwus",
"createdDate": "2020-04-08T14:17:51.869Z",
"__v": 0,
},
{
"_id": "5e8de4204396310017564a2b",
"type": 0,
"location": [
24.910688,
67.0310973
],
"title": "Nazimabad, Karachi, Pakistan",
"googlePlaceId": "ChIJzZudRr0_sz4R81KZ48Ylk3Q",
"createdDate": "2020-04-08T14:48:00.557Z",
"__v": 0,
},
{
"_id": "5e8de4364396310017564a2d",
"type": 0,
"location": [
24.9180271,
67.0970916
],
"title": "Gulshan-e-Iqbal, Karachi, Pakistan",
"googlePlaceId": "ChIJsda_CLg4sz4RIghXwgIae5k",
"createdDate": "2020-04-08T14:48:22.979Z",
"__v": 0,
},
{
"_id": "5e8dea79894854524cc554e0",
"type": 0,
"location": [
24.9343322,
67.177173
],
"title": "Malir Cantt Check Post No 6, Malir Link to Super Highway, Karachi, Pakistan",
"googlePlaceId": "ChIJJ7BbsyQ4sz4RvpkV9Ig_aU4",
"createdDate": "2020-04-08T15:15:05.360Z",
"__v": 0,
}**
Visited Places DATA
{
"_id":"5e90998f8bc84d0017a6d2f3",
"visitingNo":"0",
"_userId":"5e8f3ef5434f5800170c7169"
"_placeId":"5e908fdb8bc84d0017a6d2e8"
"createdDate":"2020-04-10T16:06:39.231+00:00"
"__v":"0"
},
{
"_id":"5e90998f8bc84d0017a6d2f3",
"visitingNo":"0",
"_userId":"5e8f3ef5434f5800170c7169"
"_placeId":"5e908fdb8bc84d0017a6d2e8"
"createdDate":"2020-04-10T16:06:39.231+00:00"
"__v":"0"
},
{
"_id":"5e90998f8bc84d0017a6d2f3",
"visitingNo":"0",
"_userId":"5e8f3ef5434f5800170c7169"
"_placeId":"5e908fdb8bc84d0017a6d2e8"
"createdDate":"2020-04-10T16:06:39.231+00:00"
"__v":"0"
},
MY CODE
const palace = placeData.aggregate([
{
$lookup:{
from: `${visitplaceData}`,
// localField: "_id",
// foreignField: "_placeId",
let : {
"placeId" : "$_id"
},
pipeline : [
{ $sort: { visitingNo : -1 } },
{
$match : {
$expr : {
$and : [
{$eq: [ "$_placeId", "$$placeId" ]},
{"_userId": body.user._id}
]
}
}
},
],
as: "places"
}
}
])

Json array iteration in futon

I am using CocuhDB I have this document structure
{"master": false,
"type": "a",
"company": 9,
"products": [
{
"unit": {
"id": 9,
"isMp": false,
"_id": "40109daadce8d3671a1aeca35bbb1438"
},
"article": {
"id": 1132,
"id_provider": 0,
"isMp": false,
"id_unit": 9,
"weight": 0,
"_id": "eb1718f96375b01af5552cf3f4c2d86b",
"code": "ME021",
"type_article": 2
},
"order": 1,
"warehouse_company": {
"id": 9,
"_id": "ebce7557ff95203ac5d03f294381d6ed"
},
"article_code": "ME021",
"provider": {
"id": 2313,
"isMp": false
},
"qty": 20.5,
"warehouse": {
"id": 18,
"isMp": false
}
}, {
"unit": {
"id": 9,
"isMp": false,
"_id": "40109daadce8d3671a1aeca35bbb1438"
},
"article": {
"id": 1132,
"id_provider": 0,
"isMp": false,
"id_unit": 9,
"weight": 0,
"_id": "eb1718f96375b01af5552cf3f4c2d86b",
"code": "ME099",
"type_article": 2
},
"order": 1,
"warehouse_company": {
"id": 9,
"isMp": false
},
"article_code": "ME021",
"provider": {
"id": 2313,
"isMp": false,
"_id": "657abbdfb4c713a9baa1ffd7329319c0"
},
"qty": 20.5,
"warehouse": {
"id": 18,
"isMp": false,
"_id": "9f70abb04a0243a1cd997b6430fb2207"
}
}
]
}
products field coulb be one or ten.
I need to find all the documents where
doc.products[n].warehouse.id == 18
But I dont know how to do it using Futon.
I am trying something like :
function(doc) {
var product, value;
if (doc.type != master && doc.type == "a" && doc.company == 9) {
for (product in doc.products) {
value= doc.prices[producto];
emit(value, doc );
}
}
}
But It does not work .
What I am doing wrong?
You can use view like this. This is an example. Not a solution
function(doc) {
var product, value;
if (doc.type != "master" && doc.type == "a" && doc.company == 9 && doc.products && Array.isArray(doc.products)) {
doc.products.forEach(function(product) {
Object.keys(product).forEach(function(key) {
emit([key, product[key].id]);
});
});
}
}
Will create output like
{
"total_rows": 16,
"offset": 0,
"rows": [
{
"key": [
"article",
1132
],
"id": "check",
"value": null
},
{
"key": [
"article",
1132
],
"id": "check",
"value": null
},
{
"key": [
"article_code",
null
],
"id": "check",
"value": null
},
{
"key": [
"article_code",
null
],
"id": "check",
"value": null
},
{
"key": [
"order",
null
],
"id": "check",
"value": null
},
{
"key": [
"order",
null
],
"id": "check",
"value": null
},
{
"key": [
"provider",
2313
],
"id": "check",
"value": null
},
{
"key": [
"provider",
2313
],
"id": "check",
"value": null
},
{
"key": [
"qty",
null
],
"id": "check",
"value": null
},
{
"key": [
"qty",
null
],
"id": "check",
"value": null
},
{
"key": [
"unit",
9
],
"id": "check",
"value": null
},
{
"key": [
"unit",
9
],
"id": "check",
"value": null
},
{
"key": [
"warehouse",
18
],
"id": "check",
"value": null
},
{
"key": [
"warehouse",
18
],
"id": "check",
"value": null
},
{
"key": [
"warehouse_company",
9
],
"id": "check",
"value": null
},
{
"key": [
"warehouse_company",
9
],
"id": "check",
"value": null
}
]
}
You can search for " warehouse" with id 18 like
using key=["warehouse",18]

Resources