I have a model with this schema:
class Treatment
include Mongoid::Document
field :value, type: Money # money-rails gem
end
That value field get saved to the db as value: {"cents"=>313, "currency_iso"=>"EUR"}
I would like find all treatments and sort them by the cents value.
Right now this is how I do it:
Treatment.collection.find().sort({value: { :cents => 1 }})
This is using the Moped driver. How can I do this using plain Mongoid?
Edit1.
[6] pry(main)> Treatment.all.only(:value).asc('value.cents').entries
=> [#<Treatment _id: 515854c2a1d24ccb1f000005, value: {"cents"=>2849, "currency_iso"=>"EUR"}>,
#<Treatment _id: 515854c2a1d24ccb1f000006, value: {"cents"=>313, "currency_iso"=>"EUR"}>,
#<Treatment _id: 515854c2a1d24ccb1f00000f, value: {"cents"=>1214, "currency_iso"=>"EUR"}>,
#<Treatment _id: 515854c2a1d24ccb1f000010, value: {"cents"=>1795, "currency_iso"=>"EUR"}>,
#<Treatment _id: 515854c2a1d24ccb1f000011, value: {"cents"=>105, "currency_iso"=>"EUR"}>,
#<Treatment _id: 515854c2a1d24ccb1f000012, value: {"cents"=>2547, "currency_iso"=>"EUR"}>
Edit2.
mongodb: stable 2.4.1-x86_64
mongoid (3.1.2)
Use the dot syntax:
Treatment.all.asc('value.cents')
edit:
Full example:
require 'mongoid'
Mongoid.load!("mongoid.yml", :development)
class Treatment
include Mongoid::Document
field :value, type: Hash
end
Treatment.delete_all
15.times do
Treatment.create(value: {cents: rand(3000), currency_iso: "EUR" })
end
p Treatment.all.only(:value).asc('value.cents').map{|t| t.value["cents"] }
Related
This thread states that it is not a very good idea to create _id in a sub-document of MongoDB.
Mongo _id for subdocument array
I have locations and their reviews in a collection:
So, what would be the way to find a unique sub-document?
What can be set as a primary key for review sub-document?
var mongoose = require('mongoose')
var openingClosingTimeSchema = new mongoose.Schema(
{
days: {type: String, required: true},
opening: String,
closing: String,
closed: {type: String, required: true}
}
)
var reviewSchema = new mongoose.Schema(
{
author: String,
rating: {type: Number, required: true, min: 0, max: 5},
reviewText: String,
createdOn: {type: Date, default: Date.now}
}
)
var locationSchema = new mongoose.Schema(
{
// 'required' keyword is for validation.
name: {type: String, required: true},
address: String,
// 'default' keyword can be with or without quotes.
// When defining multiple properties for a field, {} are required.
rating: {type: Number, default: 0, min: 0, max: 5},
facilities: [String],
// Nest 'openingClosingTimeSchema' under 'locationSchema'.
openingTimes: [openingClosingTimeSchema],
// Nest 'reviewSchema' under 'locationSchema'.
reviews: [reviewSchema]
}
)
it is not a very good idea to create _id in a sub-document of MongoDB
This is not a universally applicable guideline.
If you need to identify subdocuments in an array, an _id field would be helpful (or any other field that would serve the same function).
If you don't need to identify subdocuments, you don't need an identification field.
Since you are in the first category it's perfectly ok to have an _id field in your use case.
Is it possible to use enum validation on type: [String]?
Example:
var permitted = ['1','2','3'];
var exampleSchema = new Schema({
factors: {
type: [String],
enum: permitted,
required: "Please specify at least one factor."
}
});
I would have expected that factors would only be able to contain the values in permitted.
This is working fine for me (mongoose#4.1.8)
var schema = new mongoose.Schema({
factors: [{type: String, enum: ['1', '2', '3'], required: ...}]
...
})
Note I'm using an Array of Objects
As of mongoose version 5.0.6 and higher, the OP issue now works!
factors: {
type: [String],
enum: permitted,
required: "Please specify at least one factor."
}
Reference
https://github.com/Automattic/mongoose/issues/6204#issuecomment-374690551
TRY THIS
let inventory_type_enum = ["goods", "services"];
inventory_type: {
type: String,
enum: inventory_type_enum,
validate: {
// validator: (inventory_type) => !inventory_type.enum.includes(inventory_type),
validator: (inventory_type) => inventory_type_enum.includes(inventory_type),
message: languages('general_merchandise_model','inventory_type')
},
required : [true, languages('general_merchandise_model','inventory_type_required')],
},
Mongoose before version 4.0 didn't support validation on Schema static methods like .update, .findByIdAndUpdate, .findOneAndUpdate.
But it supports on instance method document.save().
So, either use document.save() for inbuilt initiating validation
or this { runValidators: true } with methods like .update, .findByIdAndUpdate, .findOneAndUpdate.
reference:
Mongoose .update() does not trigger validation checking
if you have enuns or you have object enuns
brand: {
type: String,
required: true,
enum: Object.values(TypeBrandEnum)
},
you can use something like this
{
factors: [
{
type: [String],
enum: ['1', '2', '3'],
},
],
}
I am using Angularjs to update the following expressjs Team model, but one weird thing is that when I PUT the first one to the database, it works.
var TeamSchema = new Schema({
title: {
type: String,
unique: true
},
image: String,
homeColor: String,
guestColor: String,
thirdColor: String,
created: {
type: Date,
default: Date.now
},
});
If the database consists of exactly one data, it will have the following errors:
{ [MongoError: E11000 duplicate key error index: acleague.teams.$prefix_1 dup key: { : null }]
name: 'MongoError',
err: 'E11000 duplicate key error index: acleague.teams.$prefix_1 dup key: { : null }',
code: 11000,
n: 0,
lastOp: { _bsontype: 'Timestamp', low_: 1, high_: 1399820159 },
connectionId: 69575,
ok: 1 }
I can sure that I don't have an $prefix_1 attr for team model.
Anyone can help me solve this problem? It already spends me lots of time of it.
I'm having some problems using mongoid-3.0.6 with polymorphic fields.
Using rails 3.2.8 and ruby 1.9.3
Using a normal polymorphic relation:
class Shirt
include Mongoid::Document
field :name, localize: true
belongs_to :itemizable, polymorphic: true
end
class Item
include Mongoid::Document
field :price, type: Float
field :quantity, type: Integer, :default => 1
has_one :product, as: :itemizable
accepts_nested_attributes_for :product
end
The same association is available through the metadata:
>> Item.reflect_on_association(:product)
#<Mongoid::Relations::Metadata
autobuild: false,
class_name: Product,
cyclic: nil,
dependent: nil,
inverse_of: nil,
key: _id,
macro: has_one,
name: product,
order: nil,
polymorphic: true,
relation: Mongoid::Relations::Referenced::One,
setter: product=,
versioned: false>
>> item = Item.new
#<Item _id: 50606c1668ce87692e000003, _type: nil, created_at: nil, updated_at: nil, deleted_at: nil, price: nil, quantity: 1>
but when i run
>> item.product = Shirt.new or >> item.build_product
i got always the same error
NameError: uninitialized constant Product
Full stack error
Any thoughts?
Thanks in advance.
Solved
Found the motive
Need to add the class_name to the relation
has_one :product, as: :itemizable, class_name: "Toy"
class Account
include Mongoid::Document
include Geocoder::Model::Mongoid
geocoded_by :zip
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
before_validation :pass_confirm
after_validation :geocode_check
before_create :assign_subs
field :email, type: String
field :type, type: String
field :zip, type: String
field :oldzip, type: String
field :coordinates, type: Array
field :latitude, type: Float
field :longitude, type: Float
auto_increment :num, collection: :account_nums
index :num, unique: true
has_many :submissions
mount_uploader :photo, PhotoUploader
def self.find_by_num(num)
Account.where(num: num).first
end
protected
def pass_confirm
self.password_confirmation ||= self.password
end
def geocode_check
if self.oldzip != self.zip
self.oldzip = self.zip
self.geocode
end
end
def assign_subs
binding.pry
Submission.where(email: self.email).each do |sub|
sub.zip = self.zip
self.submissions << sub
end
end
end
--
class Submission
include Mongoid::Document
include Mongoid::Search
include Mongoid::Timestamps::Created
include Geocoder::Model::Mongoid
geocoded_by :zip
before_validation :fix_rate
after_validation :geocode
search_in :message, tags: :name
field :email, type: String
field :rate, type: String
field :message, type: String
field :type, type: String
field :zip, type: String
field :coordinates, type: Array
field :latitude, type: Float
field :longitude, type: Float
auto_increment :num, collection: :submission_nums
index :num, unique: true
has_and_belongs_to_many :tags
belongs_to :account
mount_uploader :photo, PhotoUploader
protected
def fix_rate
self.rate = self.rate.sub(/[^\d]*/, '').sub(/(\d*).*/, '\1')
end
end
--
pry(#<Account>)> self.submissions << Submission.first
=> [#<Submission _id: 4e751df86066252059000054, _type: nil, created_at: 2011-09-17 22:23:52 UTC, _keywords: ["tfnwuaty"], email: "krisbltn#gmail.com", rate: "49", message: "tfnwuaty", type: "person", zip: nil, coordinates: nil, latitude: nil, longitude: nil, num: 1, tag_ids: [], account_id: BSON::ObjectId('4e751e0d6066252059000059'), photo: "lawrence.jpg">]
pry(#<Account>)> self.submissions
=> []
as you see above, when trying to add a child document it doesn't get saved. Any ideas as to what could be going on?
Also- this is a has_many / belongs_to relationship, and when I change it to has_and_belongs_to_many it seems to work fine.
My guess is that you've upgraded Mongoid, but haven't read the upgrading docs.
Add , :autosave => true to Account's relation with Submission.
class Account
include Mongoid::Document
has_many :submissions, :autosave => true
end
class Submission
include Mongoid::Document
belongs_to :account
end
Account.delete_all
Submission.delete_all
Submission.create
account = Account.new
account.submissions << Submission.first
account.save
Submission.first.account == account
This was also submitted as a GitHub issue. Tsk tsk.