MongoDB: Object Types

MongoDB Object Types and Commands

Table of Contents



1. Object Types Overview

Oracle has many object types (tables, views, procedures, packages and so on). MongoDB has fewer, and some Oracle objects have no MongoDB equivalent. This table shows how they map:

MongoDBOracle
DatabaseSchema (user)
CollectionTable
Schema validation ($jsonSchema)Constraints (NOT NULL, CHECK)
IndexIndex
Counter collection (manual)Sequence
ViewView
On-demand materialized view ($merge)Materialized view
Change streams / Atlas triggersTrigger
User / RoleUser / Role
No equivalent (logic lives in the application)Procedure, Function, Package
No equivalentSynonym, Database link, Tablespace
Capped collection, TTL index, Time series collectionNo direct equivalent

2. Database (Schema), Users and Roles

A MongoDB database is created automatically when you first store data in it. In Oracle, a schema is created together with its user. Run the MongoDB user and role commands inside the database you want to give access to.

MongoDBOracle
// List the databases
show dbs
-- List the schemas (users)
SELECT username FROM all_users;
// Create / switch to a database
use myFirstDB
-- Create a schema (user)
CREATE USER myfirstdb IDENTIFIED BY "Password#123"
  QUOTA UNLIMITED ON users;
GRANT CREATE SESSION, CREATE TABLE TO myfirstdb;
// Show the current database
db
-- Show the current schema
SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA')
FROM dual;
// Create a user
use myFirstDB
db.createUser({
  user: "appuser",
  pwd: passwordPrompt(),
  roles: [ { role: "readWrite", db: "myFirstDB" } ]
})
-- Create a user
CREATE USER appuser IDENTIFIED BY "Password#123";
GRANT CREATE SESSION TO appuser;
GRANT SELECT, INSERT, UPDATE, DELETE
  ON myfirstdb.students TO appuser;
// Create a custom role
db.createRole({
  role: "studentReader",
  privileges: [
    { resource: { db: "myFirstDB", collection: "students" },
      actions: [ "find" ] }
  ],
  roles: []
})
-- Create a custom role
CREATE ROLE student_reader;
GRANT SELECT ON myfirstdb.students TO student_reader;
// Give the role to a user
db.grantRolesToUser("appuser", [ "studentReader" ])
-- Give the role to a user
GRANT student_reader TO appuser;
// List users and roles
show users
show roles
-- List users and roles
SELECT username FROM dba_users;
SELECT role FROM dba_roles;
// Drop a user and a role
db.dropUser("appuser")
db.dropRole("studentReader")
-- Drop a user and a role
DROP USER appuser CASCADE;
DROP ROLE student_reader;
// Drop the current database
db.dropDatabase()
-- Drop the schema and all its objects
DROP USER myfirstdb CASCADE;

3. Collection (Table)

MongoDB collections have no fixed columns, so there is no ALTER TABLE ... ADD COLUMN. A new field simply appears when you insert or update a document with it.

MongoDBOracle
// Create a collection
db.createCollection("students")
-- Create a table
CREATE TABLE students (
  name   VARCHAR2(50),
  age    NUMBER,
  course VARCHAR2(20)
);
// Add a new field
// (no command needed, just update a document)
db.students.updateMany(
  {}, { $set: { status: "active" } }
)
-- Add a new column
ALTER TABLE students
  ADD (status VARCHAR2(20));
// Rename a field
db.students.updateMany(
  {}, { $rename: { course: "subject" } }
)
-- Rename a column
ALTER TABLE students
  RENAME COLUMN course TO subject;
// Remove a field from all documents
db.students.updateMany(
  {}, { $unset: { status: "" } }
)
-- Drop a column
ALTER TABLE students DROP COLUMN status;
// Rename a collection
db.students.renameCollection("learners")
-- Rename a table
ALTER TABLE students RENAME TO learners;
// Show collection statistics
db.students.stats()
-- Show table size
SELECT segment_name, bytes/1024/1024 AS size_mb
FROM user_segments
WHERE segment_name = 'STUDENTS';
// Drop a collection
db.students.drop()
-- Drop a table
DROP TABLE students PURGE;

4. Constraints (Schema Validation)

MongoDB does not have NOT NULL or CHECK constraints. Instead you add a validation rule to the collection with $jsonSchema. Documents that break the rule are rejected. Note: in mongosh a plain number such as 20 is stored as a double, so the rule uses number and not int.

MongoDBOracle
// Create a collection with validation
// (name and age required, age at least 1)
db.createCollection("students", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: [ "name", "age" ],
      properties: {
        name: { bsonType: "string" },
        age:  { bsonType: "number", minimum: 1 }
      }
    }
  }
})
-- Create a table with constraints
CREATE TABLE students (
  name   VARCHAR2(50) NOT NULL,
  age    NUMBER NOT NULL
         CONSTRAINT chk_age CHECK (age >= 1),
  course VARCHAR2(20)
);
// Add validation to an existing collection
db.runCommand({
  collMod: "students",
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: [ "name" ]
    }
  }
})
-- Add a constraint to an existing table
ALTER TABLE students
  MODIFY (name NOT NULL);
ALTER TABLE students
  ADD CONSTRAINT chk_age CHECK (age >= 1);
// Unique constraint (a unique index)
db.students.createIndex(
  { name: 1 }, { unique: true }
)
-- Unique constraint
ALTER TABLE students
  ADD CONSTRAINT uq_students_name UNIQUE (name);
// Primary key
// _id is the primary key and is created automatically
db.students.find({ _id: ObjectId("6ae9e9564b0e99873596e6f2") })

// Foreign key: not supported.
// Store the related _id and check it in the application.
-- Primary key and foreign key
ALTER TABLE students
  ADD CONSTRAINT pk_students PRIMARY KEY (student_id);
ALTER TABLE students
  ADD CONSTRAINT fk_students_course
  FOREIGN KEY (course_id) REFERENCES courses (course_id);

5. Indexes

MongoDB automatically creates an index on _id. In createIndex, 1 means ascending and -1 means descending. MongoDB names an index after its fields, for example name_1.

MongoDBOracle
// Single field index
db.students.createIndex({ name: 1 })
-- Single column index
CREATE INDEX idx_students_name
  ON students (name);
// Compound index
db.students.createIndex(
  { course: 1, age: -1 }
)
-- Composite index
CREATE INDEX idx_students_course_age
  ON students (course, age DESC);
// Unique index
db.students.createIndex(
  { name: 1 }, { unique: true }
)
-- Unique index
CREATE UNIQUE INDEX uq_students_name
  ON students (name);
// List the indexes
db.students.getIndexes()
-- List the indexes
SELECT index_name, uniqueness
FROM user_indexes
WHERE table_name = 'STUDENTS';
// Check whether a query uses an index
db.students.find({ name: "Ravi" }).explain("executionStats")
-- Check whether a query uses an index
EXPLAIN PLAN FOR
SELECT * FROM students WHERE name = 'Ravi';
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
// Drop an index
db.students.dropIndex("name_1")
-- Drop an index
DROP INDEX idx_students_name;

6. Sequences

MongoDB has no sequence object. Each document already gets a unique _id. If you need a number such as 1, 2, 3, the usual pattern is a small counter collection that you increase with $inc.

MongoDBOracle
// Create the counter
db.counters.insertOne(
  { _id: "student_id", seq: 0 }
)
-- Create a sequence
CREATE SEQUENCE student_seq
  START WITH 1 INCREMENT BY 1;
// Get the next value
db.counters.findOneAndUpdate(
  { _id: "student_id" },
  { $inc: { seq: 1 } },
  { returnDocument: "after" }
)
-- Get the next value
SELECT student_seq.NEXTVAL FROM dual;
// Drop the counter
db.counters.drop()
-- Drop the sequence
DROP SEQUENCE student_seq;

7. Views

A MongoDB view is read-only and is built from an aggregation pipeline. Its data is calculated each time you query it.

MongoDBOracle
// Create a view
db.createView(
  "cs_students", "students",
  [ { $match: { course: "CS" } } ]
)
-- Create a view
CREATE OR REPLACE VIEW cs_students AS
SELECT * FROM students
WHERE course = 'CS';
// Query the view
db.cs_students.find()
-- Query the view
SELECT * FROM cs_students;
// List the views
db.getCollectionInfos({ type: "view" })
-- List the views
SELECT view_name FROM user_views;
// Drop the view
db.cs_students.drop()
-- Drop the view
DROP VIEW cs_students;

8. Materialized Views

MongoDB has no CREATE MATERIALIZED VIEW command. The closest option is an on-demand materialized view: run an aggregation that ends with $merge to store the result in a collection, and run it again whenever you want to refresh.

MongoDBOracle
// Create (and refresh) the summary collection
db.students.aggregate([
  { $group: { _id: "$course", total: { $sum: 1 } } },
  { $merge: {
      into: "course_summary",
      whenMatched: "replace",
      whenNotMatched: "insert"
  } }
])
-- Create a materialized view
CREATE MATERIALIZED VIEW course_summary
  BUILD IMMEDIATE
  REFRESH COMPLETE ON DEMAND
AS
SELECT course, COUNT(*) AS total
FROM students
GROUP BY course;
// Query the result
db.course_summary.find()
-- Query the result
SELECT * FROM course_summary;
// Refresh: run the same aggregate again
-- Refresh
EXEC DBMS_MVIEW.REFRESH('COURSE_SUMMARY', 'C');
// Drop
db.course_summary.drop()
-- Drop
DROP MATERIALIZED VIEW course_summary;

9. Triggers

A self-managed MongoDB server has no database triggers. You can react to changes in two ways: a change stream (your application listens for inserts, updates and deletes, and it needs a replica set), or Atlas Database Triggers if you use MongoDB Atlas.

MongoDBOracle
// Listen for new documents (change stream)
const cursor = db.students.watch(
  [ { $match: { operationType: "insert" } } ]
)
while (!cursor.isClosed()) {
  const change = cursor.tryNext()
  if (change) printjson(change.fullDocument)
}
-- Create a trigger
CREATE OR REPLACE TRIGGER trg_students_audit
AFTER INSERT ON students
FOR EACH ROW
BEGIN
  INSERT INTO students_audit (name, action_date)
  VALUES (:NEW.name, SYSDATE);
END;
/

No list command. Atlas triggers are managed in the Atlas console or Atlas CLI.

-- List the triggers
SELECT trigger_name, status
FROM user_triggers;
// Stop listening
cursor.close()
-- Disable or drop the trigger
ALTER TRIGGER trg_students_audit DISABLE;
DROP TRIGGER trg_students_audit;

10. Procedures, Functions and Packages

MongoDB has no stored procedures, functions or packages. The business logic normally lives in the application code (Node.js, Python, Java and so on), or in Atlas Functions if you use Atlas. The old db.system.js feature for storing server-side JavaScript is deprecated, so do not use it for new work.

MongoDBOracle

Procedure: no equivalent. The application runs the insert itself:

db.students.insertOne(
  { name: "Ravi", age: 20, course: "CS" }
)
-- Create a procedure
CREATE OR REPLACE PROCEDURE add_student (
  p_name   VARCHAR2,
  p_age    NUMBER,
  p_course VARCHAR2
) AS
BEGIN
  INSERT INTO students (name, age, course)
  VALUES (p_name, p_age, p_course);
  COMMIT;
END;
/

-- Run it
EXEC add_student('Ravi', 20, 'CS');

Function: no equivalent. Use a command or an aggregation from the application:

db.students.countDocuments()
-- Create a function
CREATE OR REPLACE FUNCTION get_student_count
RETURN NUMBER AS
  v_count NUMBER;
BEGIN
  SELECT COUNT(*) INTO v_count FROM students;
  RETURN v_count;
END;
/

-- Run it
SELECT get_student_count FROM dual;

Package: no equivalent. Group the logic in a module or class in your application.

-- Package specification
CREATE OR REPLACE PACKAGE student_pkg AS
  PROCEDURE add_student (
    p_name VARCHAR2, p_age NUMBER, p_course VARCHAR2);
  FUNCTION get_student_count RETURN NUMBER;
END student_pkg;
/

-- Package body
CREATE OR REPLACE PACKAGE BODY student_pkg AS
  PROCEDURE add_student (
    p_name VARCHAR2, p_age NUMBER, p_course VARCHAR2) AS
  BEGIN
    INSERT INTO students (name, age, course)
    VALUES (p_name, p_age, p_course);
    COMMIT;
  END;

  FUNCTION get_student_count RETURN NUMBER AS
    v_count NUMBER;
  BEGIN
    SELECT COUNT(*) INTO v_count FROM students;
    RETURN v_count;
  END;
END student_pkg;
/

Nothing to list or drop in the database.

-- List and drop
SELECT object_name, object_type
FROM user_objects
WHERE object_type IN ('PROCEDURE','FUNCTION','PACKAGE','PACKAGE BODY');

DROP PROCEDURE add_student;
DROP FUNCTION get_student_count;
DROP PACKAGE student_pkg;

11. List All Objects

MongoDBOracle
// List collections and views
show collections

// With the type (collection, view, timeseries)
db.getCollectionInfos()
-- List all objects with their type
SELECT object_name, object_type, status
FROM user_objects
ORDER BY object_type, object_name;
// Count the collections
db.getCollectionNames().length
-- Count the objects by type
SELECT object_type, COUNT(*)
FROM user_objects
GROUP BY object_type;

12. MongoDB-Specific Objects

These MongoDB objects have no direct Oracle object type. The Oracle column shows the closest way to get the same result.

MongoDBOracle (closest option)
// Capped collection (fixed size, the oldest
// documents are removed automatically)
db.createCollection("logs", {
  capped: true, size: 1048576, max: 1000
})
-- No direct equivalent. Delete old rows with a job
DELETE FROM logs
WHERE log_date < SYSDATE - 7;
COMMIT;
// TTL index (documents are deleted automatically
// 3600 seconds after createdAt)
db.sessions.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 3600 }
)
-- No direct equivalent. Schedule a cleanup job
BEGIN
  DBMS_SCHEDULER.CREATE_JOB (
    job_name        => 'PURGE_SESSIONS',
    job_type        => 'PLSQL_BLOCK',
    job_action      => 'BEGIN
      DELETE FROM sessions
      WHERE created_at < SYSDATE - 1/24;
      COMMIT; END;',
    repeat_interval => 'FREQ=MINUTELY;INTERVAL=10',
    enabled         => TRUE);
END;
/
// Time series collection
db.createCollection("sensor_data", {
  timeseries: {
    timeField: "ts",
    metaField: "sensor",
    granularity: "minutes"
  }
})
-- No direct equivalent. Use a table partitioned by time
CREATE TABLE sensor_data (
  ts     TIMESTAMP,
  sensor VARCHAR2(30),
  value  NUMBER
)
PARTITION BY RANGE (ts)
INTERVAL (NUMTODSINTERVAL(1, 'DAY'))
(PARTITION p0 VALUES LESS THAN
  (TIMESTAMP '2026-01-01 00:00:00'));

Note: Oracle also has synonyms, database links and tablespaces. MongoDB has no equivalent for these.

Caution: Your use of any information or materials on this website is entirely at your own risk. It is provided for educational purposes only. It has been tested internally, however, we do not guarantee that it will work for you. Ensure that you run it in your test environment before using.
Thank you
Rajasekhar Amudala