Pythian Blog: Technical Track

Analyzing a Movie Dataset Housed on MongoDB Through GraphQL - Part 2: Application Development

If you haven't read Part 1 of the Analyzing a Movie Dataset Housed on MongoDB Through GraphQL series, please click here.

Application Development

The code was created using NodeJS, and it is integrated with Apollo Server and retrieves data from a Mongo database. I would be covering the server-side components only.

I have followed the Model-View-Controller (MVC) framework.The picture below displays the folder structure for the project. 

 

database folder: contains the files required for the application to connect to the Mongo database.

core folder: The files necessary for running GraphQL (server side components) are located in this directory.

sub-directories:

  • controller: consists of files used to connect with MongoDB and get data.
  • model: include files defining the structure of fields which we want to retrieve.
  • schema: include files that define the joins and relationships between the tables and the GraphQL schema.
  • resolver: is composed of a single file that defines the GraphQL operations.

I'll use the "users" collection as an example and walk through how to construct and connect the modules. More files can be added in the same way to include more collections (datasets).

To begin with development, let us first design our model.

file path: /src/core/model/model_users.js

code:

const mongoose = require('mongoose'); // include mongoose package

const Users = new mongoose.model('Users', // collection name in Database
{    // add the fields you want to be displayed in the UI.
  name: {
    type: {
      type: String,
      required: true
    }
  },
  email: {
    type: {
      type: String,
      required: true
    }
  }
});


module.exports = {
  Users
};

file path: /src/core/schema/schema_users.js

code:

const graphql = require('graphql'); 
const mongoose = require('mongoose');


const {
 GraphQLSchema,
 GraphQLObjectType,
 GraphQLString,
 GraphQLInt,
 GraphQLID,
 GraphQLList,
 GraphQLNonNull
} = graphql; // datatypes used in schema and resolvers.


const UsersSchema = new graphql.GraphQLObjectType({
    name: 'users', 
    description: 'Details of the user who gave an opinion about the films.',
 // add fields and provide appropriate datatypes for them.
    fields: {
        name: {type: GraphQLString}, 
        email: {type: GraphQLString}
    }
});




module.exports = { UsersSchema };

file path: /src/core/resolvers/resolver.js

code:

const graphql = require('graphql');
const UsersController = require("../controller/controller_users.js");
const {  UsersSchema } = require('../schema/schema_users.js');
const {
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLString,
  GraphQLInt,
  GraphQLID,
  GraphQLList,
  GraphQLNonNull
} = graphql;


// Create a root query, specifying the structure and functions in the UI.
const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: {
    user: {
      type: UsersSchema,
      args: {
        name: {
          name: "name",
          required: true,
          type: GraphQLString
        }
      },
      async resolve(parent, args) {
        return await UsersController.getUserByName(args)
      }
    },
    users: {
      type: new GraphQLList(UsersSchema),
      async resolve(parent, args) {
        return await UsersController.getUsers()
      }
    }
  }
});

const schema = new graphql.GraphQLSchema({
  query: RootQuery
});

module.exports = {
  schema
};

file path: /src/core/controller/controller_user.js

code:

// Get Data Model
const { Users } = require('../model/model_users.js')

// Get all Users
async function getUsers() {
  try {
    console.log("Fetching all the Users")
    const users = await Users.find()
    console.log(`Total Records: ${users.length}`)
    return users
  } catch (e) {
    console.error(e);
  }
}

// Get a single User by name
async function getUserByName(args) {
  try {
    console.log("Searching for the User by name...")
    console.log(args)
    const arg_name = args.name
    const user = await Users.findOne({
      name: arg_name
    })
    if (user) {
      console.log(`Found a user in the collection with the name '${arg_name}'.`);
      //console.log(result);
    } else {
      console.log(`No user found with the name '${arg_name}'`);
    }
    return user
  } catch (e) {
    console.error(e);
  }
}

module.exports = {
  getUsers,
  getUserByName
};

Now that we've created the model and schema, let's write the code to connect to the Mongo database.

file path:  /src/database/mongo_db_connection.js

code:

const mongoose = require('mongoose');

const url = "mongodb://mongodb-service:27017/" // connection url
const db_name = "test"; // database name.
const uri = url + db_name;

module.exports.connection = async () => {
  try {
    mongoose.set('debug', true); // displays the query fired on DB
    await mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });
    console.log('Database Connected Successfully');
  } catch (error) {
    console.log(error);
    throw error;
  }
}

module.exports.isValidObjectId = (id) => {
  return mongoose.Types.ObjectId.isValid(id);
}

Now that we've completed all of the setup, let's construct a main file to configure the Apollo server and connect all of the code files.

file path:  /src/index.js

code:

const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
const { connection } = require('./database/mongo_db_connection.js');
const { schema } = require("./core/resolvers/resolver.js");


try 
{
 connection(); //db connectivity
const PORT = process.env.PORT || 10000  
 async function startApolloServer() {
 const server = new ApolloServer(
 {
 schema: schema, // map the schema from resolver 
 }); 
 const { url } = await startStandaloneServer(server, {listen: { port: PORT }});
 console.log(`Server is running and query at ${url}`);
 }
 startApolloServer(); 
}


catch(e) 
{
 console.log(e);


Code testing in a local environment:

Run the command while in the root folder: npm start

We can view the application in browser: http://localhost:10000/

Now that our application is running locally, let's move onto containerizing and deploying it.

No Comments Yet

Let us know what you think

Subscribe by email