{"id":19142218,"url":"https://github.com/eldoy/mongocore","last_synced_at":"2025-10-21T07:28:28.470Z","repository":{"id":56884314,"uuid":"76859068","full_name":"eldoy/mongocore","owner":"eldoy","description":"MongoDB ORM implementation on top of the Ruby MongoDB driver. Very fast and light weight.","archived":false,"fork":false,"pushed_at":"2018-01-24T17:28:20.000Z","size":266,"stargazers_count":5,"open_issues_count":14,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-03T08:27:10.385Z","etag":null,"topics":["mongodb","mongodb-orm","mongodb-ruby-driver","odm","orm","rails","ruby","ruby-mongodb-driver","schema"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eldoy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-19T12:10:44.000Z","updated_at":"2024-07-21T00:50:03.000Z","dependencies_parsed_at":"2022-08-20T23:40:33.700Z","dependency_job_id":null,"html_url":"https://github.com/eldoy/mongocore","commit_stats":null,"previous_names":["fugroup/mongocore"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eldoy%2Fmongocore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eldoy%2Fmongocore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eldoy%2Fmongocore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eldoy%2Fmongocore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eldoy","download_url":"https://codeload.github.com/eldoy/mongocore/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252788404,"owners_count":21804280,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mongodb","mongodb-orm","mongodb-ruby-driver","odm","orm","rails","ruby","ruby-mongodb-driver","schema"],"created_at":"2024-11-09T07:26:21.681Z","updated_at":"2025-10-21T07:28:23.396Z","avatar_url":"https://github.com/eldoy.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mongocore Ruby Database Driver\nA new MongoDB ORM implementation on top of the [latest MongoDB Ruby driver.](https://docs.mongodb.com/ruby-driver/master/quick-start/) Very fast and light weight.\n\nThe perfect companion for Rails, Sinatra, Susana or other Rack-based web frameworks.\n\n### Features\nWith Mongocore you can do:\n\n* Insert, update and delete\n* Finding, sorting, limit, skip, defaults\n* Scopes, associations, validations, pagination\n* Read and write access control for each key\n* Request cache, counter cache, track changes\n* Automatic timestamps, tagged keys, json\n\nThe schema is specified with a YAML file which supports default values, data types, and security levels for each key.\n\nPlease read [the source code](https://github.com/fugroup/mongocore/tree/master/lib/mongocore) to see how it works, it's fully commented and very small, only 8 files, and 519 lines of fully test driven code.\n\n| Library                                | Files | Comment | Lines of code |\n| -------------------------------------- | ----- | ------- | ------------- |\n| [Mongoid](http://mongoid.com)          | 256   | 14371   | 10590         |\n| [MongoMapper](http://mongomapper.com)  | 91    | 200     | 4070          |\n| [Mongocore](http://mongocore.com)      | 8     | 275     | 519           |\n\n\u003cbr\u003e\n\nThe tests are written [using Futest,](https://github.com/fugroup/futest) try it out if you haven't, it makes testing so much fun.\n\n### Installation\n```\ngem install mongocore\n```\nor add to your Gemfile.\n\nThen in your model:\n```ruby\nclass Model\n  include Mongocore::Document\nend\n```\n\n### Settings\nMongocore has a few built in settings you can easily toggle:\n```ruby\n# Schema path is $app_root/config/db/schema/:model.yml\n# The yml files should have singular names\nMongocore.schema = File.join(Dir.pwd, 'config', 'db', 'schema')\n\n# The cache stores documents in memory to avoid db round trips\nMongocore.cache = true\n\n# The access enables the read / write access levels for the keys\nMongocore.access = true\n\n# Enable timestamps, auto-save created_at and updated_at keys\nMongocore.timestamps = true\n\n# Default sorting, last will be opposite. Should be indexed.\nMongocore.sort = {}\n\n# Pagination results per page\nMogocore.per_page = 20\n\n# Enable debug to see caching information and help\nMongocore.debug = false\n```\n\n### Usage\n\n```ruby\n# Set up connection to database engine\n# Add this code to an initializer or in your environment file\nMongocore.db = Mongo::Client.new(['127.0.0.1:27017'], :database =\u003e \"dbname_#{ENV['RACK_ENV']}\")\n\n# Logging options\nMongo::Logger.logger.level = ::Logger::INFO\nMongo::Logger.logger.level = ::Logger::FATAL\n\n# Write to log file instead of terminal\nMongo::Logger.logger = ::Logger.new('./log/mongo.log')\n\n# Create a new document\nm = Model.new\nm.duration = 59\nm.save\n\n# Insert and save in one line\nm = Model.insert(:duration =\u003e 45, :goal =\u003e 55)\nm = Model.create(params, :validate =\u003e true) # Alias\n\n# Create another document\np = Parent.new(:house =\u003e 'Nice')\np.save\n\n# Reload the model attributes from the database\np.reload\n\n# Add the parent to the model\nm.parent = p\nm.save\n\n# Finding\nquery = Model.find\nquery = Model.where # Alias\n\n# Query doesn't get executed until you call all, count, last or first\nm = query.all\na = query.featured.all\nc = query.count\nl = query.last\nf = query.first\n\n# All\nm = Model.find.all\n\n# Pagination returns an array\nm = Model.find.paginate\nm = Model.find.paginate(:per_page =\u003e 10, :page =\u003e 5)\nm.total # =\u003e Total number of results\n\n# Use each to fetch one by one\nModel.each do |m|\n  puts m\nend\n\n# each_with_index, each_with_object and map works as well\n\n# Works with finds, scopes and associations\nModel.find(:duration =\u003e 50).each{|m| puts m}\n\n# All of these can be used:\n# https://docs.mongodb.com/manual/reference/operator/query-comparison\nm = Model.find(:house =\u003e {:$ne =\u003e nil, :$eq =\u003e 'Nice'}).last\n\n# Sorting, use -1 for descending, 1 for ascending\nm = Model.find({:duration =\u003e {:$gt =\u003e 40}}, :sort =\u003e {:duration =\u003e -1}).all\nm = p.models.find(:duration =\u003e 10).sort(:duration =\u003e -1).first\n\n# Limit, pass as third option to find or chain, up to you\np = Parent.find.sort(:duration =\u003e 1).limit(5).all\np = Parent.limit(1).last\nm = p.models.find({}, :sort =\u003e {:goal =\u003e 1}, :limit =\u003e 1).first\nm = Model.sort(:goal =\u003e 1, :duration =\u003e -1).limit(10).all\n\n# First\nm = Model.find(:_id =\u003e object_id).first\nm = Model.find(object_id).first\nm = Model.find(string).first\nm = Model.find(:duration =\u003e 60, :goal =\u003e {:$gt =\u003e 0}).first\n\n# Last\nm = Model.last\nm = p.models.last\n\n# Count\nc = Model.count\nc = p.models.featured.count\n\n# Skip\nm = Model.find.skip(2).first\n\n# Attributes\nm = Model.first\nm.attributes             # =\u003e All attributes\nm.attributes(:badge)     # =\u003e Attributes with the badge tag only\nm.to_json                # =\u003e All attributes as json\n\n# Track changes\nm.duration = 33\nm.changed?\nm.duration_changed?\nm.duration_was\nm.changes\nm.saved?\nm.persisted? # Alias for saved?\nm.unsaved?\nm.new_record? # Alias for unsaved?\n\n# Validate\nm.valid?\nm.errors.any?\nm.errors\n\n# Update\nm.update(:duration =\u003e 60)\n\n# Delete\nm.delete\n\n# Many associations\nq = p.models.all\nm = p.models.first\nm = p.models.last\n\n# Scopes\nq = p.models.featured.all\nq = p.models.featured.nested.all\nm = Model.featured.first\n\n# Access\nmodel = Mongocore::Access.role(:user) do\n  # Reads and writes in the block will be with the above access level\n  Model.first\nend\n\n# In your model\nclass Model\n  include Mongocore::Document\n\n  # Validations will be run if you pass model.save(:validate =\u003e true)\n  # You can run them manually by calling model.valid?\n  # You can have multiple validate blocks if you want to\n  validate do\n    # The errors hash can be used to collect error messages.\n    errors[:duration] \u003c\u003c 'duration must be greater than 0' if duration and duration \u003c 1\n    errors[:goal] \u003c\u003c 'you need a higher goal' if goal and goal \u003c 5\n  end\n\n  # Before and after filters: :save, :delete\n  # You can have multiple blocks for each filter if needed\n  before :save, :setup\n\n  def setup\n    puts \"Before save\"\n  end\n\n  after :delete do\n    puts \"After delete\"\n  end\nend\n\n# Use pure Ruby driver, returns BSON::Document objects\nMongocore.db[:models].find.to_a\nMongocore.db[:models].find({:_id =\u003e m._id}).first\n\n# Indexing\nMongocore.db[:models].indexes.create_one(:key =\u003e 1)\nMongocore.db[:models].indexes.create_one({:key =\u003e 1}, :unique =\u003e true)\n```\n\n### Schema and models\nEach model is defined using a [YAML](http://yaml.org) schema file. This is where you define keys, defaults, description, counters, associations, access, tags, scopes and accessors.\n\nThe default schema file location is `APP_ROOT/config/db/schema/*.yml`, so if you have a model called Parent, create a yml file called parent.yml.\n\nYou can change the shema file location like this:\n```ruby\nMongocore.schema = File.join(Dir.pwd, 'your', 'schema', 'path')\n```\n\n#### Parent example schema, has many Models\n```yml\n\n# The meta is information about your model\nmeta:\n  name: parent\n  type: document\n\nkeys:\n\n  # Define the _id field for all your models. The id field (without _)\n  # is an alias to _id, but always returns a string instead of a BSON::ObjectId\n  # Any object ids as strings will be automatically converted into ObjectIds\n  # @desc: Describes the key, can be used for documentation.\n  # @type: object_id, string, integer, float, boolean, time, binary, hash, array\n  # @default: the default value for the key when you call .new\n  # @read: access level for read: all, user, owner, dev, admin, super, app\n  # @write: access level for write. Returns nil if no access, as on read\n\n  # Object ID, usually added for each model\n  _id:\n    desc: Unique id\n    type: object_id\n    read: all\n    write: app\n\n  # String key\n  world:\n    desc: Parent world\n    type: string\n    read: all\n    write: user\n\n  # If the key ends with _count, it will be used automatically when\n  # you call .count on the model as an automatic caching mechanism\n  models_count:\n    desc: Models count\n    type: integer\n    default: 0\n    read: all\n    write: app\n\n  # This field will be returned when you write models.featured.count\n  # Remember to create an after filter to keep it updated\n  models_featured_count:\n    desc: Models featured count\n    type: integer\n    default: 0\n    read: all\n    write: app\n\n# Many relationships lets you do:\n# Model.parents.all or model.parents.featured.all with scopes\nmany:\n  - models\n```\n\n\n#### Model example schema, belongs to Parent\n\n```yml\nmeta:\n  name: model\n  type: document\n\nkeys:\n  # Object ID\n  _id:\n    desc: Unique id\n    type: object_id\n    read: all\n    write: app\n\n  # Integer key with default\n  duration:\n    desc: Model duration in days\n    type: integer\n    default: 60\n    read: dev\n    write: user\n    # Add tags for keys for use with attributes\n    tags:\n    - badge\n\n  # Time key\n  expires_at:\n    desc: Model expiry date\n    type: time\n    read: all\n    write: dev\n    # Multiple tags possible: attributes(:badge, :campaigns)\n    tags:\n    - badge\n    - campaigns\n\n  # Hash key\n  location_data:\n    desc: Model location data\n    type: hash\n    read: all\n    write: user\n\n  # Counter key\n  votes_count:\n    desc: Votes count\n    type: integer\n    default: 0\n    read: all\n    write: dev\n    tags:\n    - badge\n\n  # If the key ends with _id, it is treated as a foreign key,\n  # and you can access it from the referencing model and set it too.\n  # Example: model.parent, model.parent = parent\n  parent_id:\n    desc: Parent id\n    type: object_id\n    read: all\n    write: dev\n\n# Generate accessors (attr_accessor) for each key\naccessor:\n- submittable\n- update_expires_at\n- skip_before_save\n\n# Define scopes that lets you do Models.featured.count\n# Each scope has a name, and a set of triggers\nscopes:\n\n  # This will create a .featured scope, and add :duration =\u003e 60 to the query.\n  featured:\n    duration: 60\n\n  nested:\n    goal: 10\n\n  # Any mongodb driver query is possible\n  finished:\n    duration: 60\n    goal:\n      $gt: 10\n\n  active:\n    params:\n      - duration\n    duration:\n      $ne: duration\n\n  # You can also pass parameters into the scope, as a lambda.\n  ending:\n    params:\n     - user\n    $or:\n      - user_id: user.id\n      - listener: user.id\n      - listener: user.link\n    deletors:\n      $ne: user.id\n```\n\n### Contribute\nContributions and feedback are welcome! MIT Licensed.\n\nIssues will be fixed, this library is actively maintained by [Fugroup Ltd.](http://www.fugroup.net) We are the creators of [CrowdfundHQ.](https://crowdfundhq.com)\n\nThanks!\n\n`@authors: Vidar`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feldoy%2Fmongocore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feldoy%2Fmongocore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feldoy%2Fmongocore/lists"}