Does MongoMapper or any plugin created for it support the positional operator? I have a 6-level-deep embedded document structure on my primary model and I notice that while I can use .push on my primary model to get things tacked on to the 1st level collections, I can't go beyond that without re-creating the entire collection every time I add.
I am currently assembling a 1.5 meg document in memory then saving to mongo in 1 shot. This document doesn't need to be updated at all after the initial write, but I am concerned with this massive write going out. It's taking around 8 seconds to write it all out from MM and I want to switch to just assembling the data in mongo as I progress to avoid locking the table for too long. I was hoping something was written already so I don't have to re-create my collections every time I want to add something to it.
Mongo itself supports something like: db.as.update( {"_id" : ObjectId("4de579c3c643cf0f60000001")}, {$push: {'bs.N.cs': {"_id": ObjectId("4de579c3c643cf0f60000099")} } } )
(
http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator)
Where N is the Nth element of the array/collection.
Sample code/console:
class A
include MongoMapper::Document
many :bs
end
class B
include MongoMapper::EmbeddedDocument
has_one :a
many :cs
end
class C
include MongoMapper::EmbeddedDocument
has_one :b
end
> a = A.new
> a.save
MONGODB development['as'].update({:_id=>BSON::ObjectId('4de579c3c643cf0f60000001')}, {"_id"=>BSON::ObjectId('4de579c3c643cf0f60000001'), "bs"=>[]})
> a.reload
MONGODB development['as'].find({:_id=>BSON::ObjectId('4de579c3c643cf0f60000001')})
> a.push(:bs => B.new.to_mongo)
MONGODB development['as'].update({:_id=>{"$in"=>[BSON::ObjectId('4de579c3c643cf0f60000001')]}}, {"$push"=>{:bs=>{"_id"=>BSON::ObjectId('4de579cdc643cf0f60000002')}}})
> a.reload
MONGODB development['as'].find({:_id=>BSON::ObjectId('4de579c3c643cf0f60000001')})
>
a.bs # => [#<B _id: BSON::ObjectId('4de5778dc643cf0eda000011')>]
> b = a.bs.first
> b.cs # => []
> b.push(:cs => C.new) # NoMethodError: undefined method `push' for #<B _id: BSON::ObjectId('4de5778dc643cf0eda000011')>
> b.cs << C.new # => [#<C _id: BSON::ObjectId('4de577b3c643cf0eda000013')>]
> b.save # I only want to save Bs, but its also re-saving A
MONGODB development['as'].update({:_id=>BSON::ObjectId('4de579c3c643cf0f60000001')}, {"_id"=>BSON::ObjectId('4de579c3c643cf0f60000001'), "bs"=>[{"_id"=>BSON::ObjectId('4de579cdc643cf0f60000002'), "cs"=>[{"_id"=>BSON::ObjectId('4de579efc643cf0f60000004')}]}]})
Corresponding Mongo queries:
> db.as.find( {"_id" : ObjectId("4de579c3c643cf0f60000001")} )
{ "_id" : ObjectId("4de579c3c643cf0f60000001"), "bs" : [
{
"_id" : ObjectId("4de579cdc643cf0f60000002"),
"cs" : [
{
"_id" : ObjectId("4de579efc643cf0f60000004")
}
]
}
] }
> db.as.update( {"_id" : ObjectId("4de579c3c643cf0f60000001")}, {$push: {'bs.0.cs': {"_id": ObjectId("4de579c3c643cf0f60000099")} } } )
> db.as.find( {"_id" : ObjectId("4de579c3c643cf0f60000001")} )
{ "_id" : ObjectId("4de579c3c643cf0f60000001"), "bs" : [
{
"_id" : ObjectId("4de579cdc643cf0f60000002"),
"cs" : [
{
"_id" : ObjectId("4de579efc643cf0f60000004")
},
{
"_id" : ObjectId("4de579c3c643cf0f60000099")
}
]
}
] }