Mukesh
Mukesh

Reputation: 1267

MongoDB Mongoid delete value from array

I have mongodb document like this and want to remove one element form unpublished array which is in resource_well

{
       "_id": ObjectId("4fa77c808d0a6c287d00000a"),       
       "production_status": "Unscheduled",
       "projected_air_date": null,
       "published": false,
       "resource_well": {
         "published": [

        ],
         "unpublished": {
           "0": ObjectId("4fa795038d0a6c327e00000e"),
           "1": ObjectId("4fa795318d0a6c327e00000f"),
           "2": ObjectId("4fa795508d0a6c327e000011"),
           "3": ObjectId("4fa796f48d0a6c327e000013")
        }
      },
       "segment_status": "Draft",
}

Code in controller

segment = Segment.find(params[:segment_id])
# segment.resource_well[params['resource_well_type']].class => Array   
# segment.resource_well[params['resource_well_type']].inspect => [BSON::ObjectId('4fa795038d0a6c327e00000e'), BSON::ObjectId('4fa795318d0a6c327e00000f'), BSON::ObjectId('4fa795508d0a6c327e000011'), BSON::ObjectId('4fa796f48d0a6c327e000013')]  
segment.resource_well[params['resource_well_type']].delete(params[:asset_ids])
segment.save

Not able remove an element form array

Upvotes: 0

Views: 3033

Answers (2)

Gary Murakami
Gary Murakami

Reputation: 3402

Your ODM (or ORM) provides associations for you so that you can take advantage of having the ODM manage the links for you. So you should use the associations, otherwise you risk hanging yourself. Just make sure to specify the relationship correctly, and use the generated method named by the association and its methods, e.g. resource_well.unpublished <<, resource_well.unpublished.delete. The following models and tests work for me. The inconvenience is that the delete method on the association takes an object, e.g., other.delete(object) and not a string or conditions, so if you start with a string, you have to supply an object in order to delete it. Note that other.delete_all(conditions) or other.where(conditions).delete_all remove both actual documents as well as the association, which is not what you were looking for. Anyway, hope that this helps.

Models

class Segment
  include Mongoid::Document
  field :production_status, type: String
  field :projected_air_date, type: Date
  field :published, type: Boolean
  field :segment_status, type: String
  embeds_one :resource_well
end

class ResourceWell
  include Mongoid::Document
  embedded_in :segment
  has_and_belongs_to_many :published, :class_name => 'Resource'
  has_and_belongs_to_many :unpublished, :class_name => 'Resource'
end

class Resource
  include Mongoid::Document
  field :name, type: String
end

Test

require 'test_helper'

class Object
  def to_pretty_json
     JSON.pretty_generate(JSON.parse(self.to_json))
  end
end

class SegmentTest < ActiveSupport::TestCase
  def setup
    Segment.delete_all
  end

  test 'resource_well unpublished delete' do
    res = (0..3).collect{|i| Resource.create(name: "resource #{i}")}
    seg = Segment.create(
        production_status: 'Unscheduled',
        projected_air_date: nil,
        published: false,
        resource_well: ResourceWell.new(unpublished: res[0..2]),
        segment_status: 'Draft')
    seg.resource_well.unpublished << res[3] #just an append example
    puts seg.to_pretty_json

    id = res[0]['_id'].to_s
    puts "id: #{id}"
    resource_obj = Resource.find(id)
    puts "resource: #{resource_obj.inspect}"
    Rails.logger.debug("delete: #{resource_obj.inspect}")
    seg.resource_well.unpublished.delete(resource_obj)
    puts Segment.find(:all).to_pretty_json
  end
end

Result

# Running tests:

{
  "_id": "4fa839197f11ba80a9000006",
  "production_status": "Unscheduled",
  "projected_air_date": null,
  "published": false,
  "resource_well": {
    "_id": "4fa839197f11ba80a9000005",
    "published_ids": [

    ],
    "unpublished_ids": [
      "4fa839197f11ba80a9000001",
      "4fa839197f11ba80a9000002",
      "4fa839197f11ba80a9000003",
      "4fa839197f11ba80a9000004"
    ]
  },
  "segment_status": "Draft"
}
id: 4fa839197f11ba80a9000001
resource: #<Resource _id: 4fa839197f11ba80a9000001, _type: nil, name: "resource 0">
[
  {
    "_id": "4fa839197f11ba80a9000006",
    "production_status": "Unscheduled",
    "projected_air_date": null,
    "published": false,
    "resource_well": {
      "_id": "4fa839197f11ba80a9000005",
      "published_ids": [

      ],
      "unpublished_ids": [
        "4fa839197f11ba80a9000002",
        "4fa839197f11ba80a9000003",
        "4fa839197f11ba80a9000004"
      ]
    },
    "segment_status": "Draft"
  }
]
.

Finished tests in 0.016026s, 62.3986 tests/s, 0.0000 assertions/s.

1 tests, 0 assertions, 0 failures, 0 errors, 0 skips

Upvotes: 4

Benjamin Harel
Benjamin Harel

Reputation: 2946

db.collection.update( 
  {_id : ObjectId("4fa77c808d0a6c287d00000a")}, 
  { $unset : { "resource_well.unpublished.1" : 1 }} 
);

This will remove element [1] of the array.

Also you can read how to implement it using mongoid: http://mongoid.org/docs/upgrading.html

Upvotes: 2

Related Questions