0
votes

Suppose I deleted a document or subdocument in mongodb. Can I create document / subdocument with the same _id as the deleted one? In this case, we assume, we cannot do update operation, just delete and create.

For example using Mongoid (Rails gem for mongodb) : We have Person Model

class Person
    include Mongoid::Document
    field :a, :type => String
    embeds_many :personattributes
end
class Personattribute
    include Mongoid::Document
    field :myattribute, :type => String
    embedded_in :person
end

And in my Rails controller

class MyController < ApplicationController
    ...
    @[email protected]
    ... 
    #controller will render page, an instance variable @the_attributes will be available as JSON in clientside
end

Then user does some client side data modifications. They can add 1 or more personattributes to that person data. They can do some changes on its attributes. They can delete some also. All in client side.

Then by AJAX call, user sends the modified data back in JSON format like

[{_id:"5253fd494db79bb271000009",myattribute:"test"},{...},...]

The retriever in controller retrieves the data Then totally replace the attribute list inside person with the new one. Total deletion and insertion, no update.

class MyController < ApplicationController
...
@person.personattributes.delete_all #delete all attributes a @person has
attributes=params[:attributes]
attributes.map {|attr| 
    Personattribute.new(:_id => Moped::BSON::ObjectId.from_string(attr["_id"].to_s), :myattribute => attr["myattribute"])
}

@person.personattributes=attributes
@person.save

...
end

Can I do this? It simply means, delete all, and insert all and reuse the _ids.

If not, I will be happy to get some advice on a better approach on this.

I can't do upsert since the deleted documents will need another loop to handle.

Thank you

2
Why do you want to keep the same ids? - Ismael
Because other data (model) are referring to a specific personattribute. If I change the id, then the reference will be broken. Thank you for asking that clarification - Yudho Ahmad Diponegoro

2 Answers

1
votes

Yes, you can do it but I would recommend you not to do that. It seems to have lots of security issues if someone modifies the array manually

I could send:

[{_id:"5253fd494db79bb271000009",myattribute:"test_modified"},{...},...]

or even:

[{_id:"my_new_id_1",myattribute:"test_modified"},{...},...]

which would raise an exception

Moped::BSON::ObjectId.from_string "my_new_id_1" #=> raises an Exception

Try something like:

attributes=params[:attributes]
attributes.each do |attr|
   @person.personattributes.find(attr["_id"]).myattribute = attr["myattribute"]
   #or @person.personattributes.find(attr["_id"]).try(:myattribute=,attr["myattribute"])
end

Probably in a future you want to change the action and send just the modified personattributes in the array instead of all the personattributes. What would you do then if you delete_all and rebuild personattributes with just the sent personattributes?

EDIT

This handles personattributes updates. Create or delete personattributes should go in different actions:

Create action

@person.personattributes.push Personattribute.new(my_attribute: params[:my_attribute])

Delete action

@person.personattributes.delete(params[:personattribute_id])
0
votes

Yes, you can keep using the same _id. They just need to be unique within a collection -- and that's only true for the document's _id.

Any ObjectId you might use elsewhere in an another field in a document (or in a subdocument) doesn't need to be unique, unless you've created an index where it must be unique.