5

I am new in mongodb and i want to remove the some element in array.

my document as below

{
  "_id" : ObjectId("4d525ab2924f0000000022ad"), 
  "name" : "hello", 
  "time" : [
      {
              "stamp" : "2010-07-01T12:01:03.75+02:00",
              "reason" : "new"
      },
      {
              "stamp" : "2010-07-02T16:03:48.187+03:00",
              "reason" : "update"
      },
      {
              "stamp" : "2010-07-02T16:03:48.187+04:00",
              "reason" : "update"
      },
      {
              "stamp" : "2010-07-02T16:03:48.187+05:00",
              "reason" : "update"
      },
      {
              "stamp" : "2010-07-02T16:03:48.187+06:00",
              "reason" : "update"
      }
  ]
}

in document, i want to remove first element(reason:new) and last element(06:00) .

and i want to do it using mongoquery, i am not using any java/php driver.

User
  • 31,811
  • 40
  • 131
  • 232
javaamtho
  • 382
  • 3
  • 7
  • 20

5 Answers5

6

If I'm understanding you correctly, you want to remove the first and last elements of the array if the size of the array is greater than 3. You can do this by using the findAndModify query. In mongo shell you would be using this command:

db.collection.findAndModify({
    query: { $where: "this.time.length > 3" },
    update: { $pop: {time: 1}, $pop: {time: -1} },
    new: true
});

This would find the document in your collection which matches the $where clause. The $where field allows you to specify any valid javascript method. Please note that it applies the update only to the first matched document.

You might want to look at the following docs also:

  1. http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-JavascriptExpressionsand%7B%7B%24where%7D%7D for more on the $where clause.
  2. http://www.mongodb.org/display/DOCS/Updating#Updating-%24pop for more on $pop.
  3. http://www.mongodb.org/display/DOCS/findAndModify+Command for more on findAndModify.
Ivo Smits
  • 237
  • 1
  • 10
asleepysamurai
  • 1,362
  • 2
  • 14
  • 23
  • Using `$where` is not a good idea for performance reasons, if you want to query based on array length you should keep track of that length manually. – Noah McIlraith Dec 28 '12 at 08:57
4

You could update it with { $pop: { time: 1 } } to remove the last one, and { $pop: { time : -1 } } to remove the first one. There is probably a better way to handle it though.

gnarf
  • 105,192
  • 25
  • 127
  • 161
  • thanks for reply and this is help me ..but i have one condition that i want to check before use this query, condition is if size of time array greater than 3. i am not able to determine size of time array. could you please any idea. – javaamtho Feb 10 '11 at 09:16
  • @javaamtho For the query condition part, see [this answer](http://stackoverflow.com/questions/7811163/in-mongo-db-how-do-i-find-documents-where-array-size-is-greater-than-1/15224544#15224544). – JohnnyHK Oct 20 '13 at 15:01
0

If you would like to leave these time elements, you can use aggregate command from mongo 2.2+ to retrieve min and max time elements, unset all time elements, and push min and max versions (with some modifications it could do your job):

smax=db.collection.aggregate([{$unwind: "$time"},
{$project: {tstamp:"$time.stamp",treason:"$time.reason"}},
{$group: {_id:"$_id",max:{$max: "$tstamp"}}},
{$sort: {max:1}}])

smin=db.collection.aggregate([{$unwind: "$time"},
{$project: {tstamp:"$time.stamp",treason:"$time.reason"}},
{$group: {_id:"$_id",min:{$min: "$tstamp"}}},
{$sort: {min:1}}])

db.students.update({},{$unset: {"scores": 1}},false,true)

smax.result.forEach(function(o)  
{db.collection.update({_id:o._id},{$push:
{"time": {stamp: o.max ,reason: "new"}}},false,true)})

smin.result.forEach(function(o)
{db.collection.update({_id:o._id},{$push:
{"time": {stamp: o.min ,reason: "update"}}},false,true)})
42n4
  • 1,292
  • 22
  • 26
0

db.collection.findAndModify({ query: {$where: "this.time.length > 3"}, update: {$pop: {time: 1}, $pop{time: -1}}, new: true });

convert to PHP

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
0

@javaamtho you cannot test for a size greater than 3 but only if it is exactly 3, for size greater than x number you should use the $inc operator and have a field you either 1 or -1 to in order to keep track when you remove or add items (use a separate field outside the array as below, time_count)

{
  "_id" : ObjectId("4d525ab2924f0000000022ad"), 
  "name" : "hello",
  "time_count" : 5,
  "time" : [
      {
              "stamp" : "2010-07-01T12:01:03.75+02:00",
              "reason" : "new"
      },
      {
              "stamp" : "2010-07-02T16:03:48.187+03:00",
              "reason" : "update"
      },
      {
              "stamp" : "2010-07-02T16:03:48.187+04:00",
              "reason" : "update"
      },
      {
              "stamp" : "2010-07-02T16:03:48.187+05:00",
              "reason" : "update"
      },
      {
              "stamp" : "2010-07-02T16:03:48.187+06:00",
              "reason" : "update"
      }
  ]
}
Bob
  • 671
  • 1
  • 7
  • 12
  • to check exactly size 3, are you suggesting $size. how do i remove exactly second element from time array. i am talking abt element { "stamp" : "2010-07-02T16:03:48.187+03:00", "reason" : "update" } – javaamtho Feb 11 '11 at 09:32
  • @javaamtho so the first question: I am saying to create a field in the document outside the array to keep track of the number of elements and use the $inc operator to ++ it or -- it and for the second question: I beleive you can do time.2 for the second element and just do $unset or you may have to $set to null then $pull null – Bob Feb 11 '11 at 18:09