Use MongoDB array as stack

旧城冷巷雨未停 提交于 2019-12-10 23:04:25

问题


Has anybody used MongoDB's Array type to implement a stack?

I know that I can append to an Array like so:

db.blogposts.update( {_id:5}, {$push: {comments: {by: "Abe", text:"First"}}})

Here, the end of the array is the top of the stack... I don't see a way to implement this with the top of the stack at the zero'th index, but I'd love to be wrong.

And I know that I can peek at the last value of the the array like so:

db.blogposts.find( {_id:5}, {comments: {$slice:-1}})

With an implementation like this, can I "peek" at the top of the stack in a MongoDB update statement? That would give me the semantic, "push this item on the stack if the top of the stack is X". I need this to be an atomic operation!

Any advice appreciated. Thanks!


回答1:


Unfortunately, there is currently no way to do this exactly as you have described.

As Chris Shain pointed out, https://jira.mongodb.org/browse/SERVER-2191 - "$push() to front of array" and similarly https://jira.mongodb.org/browse/SERVER-1824 - "Support for inserting into specific array index" would help, but these features are currently not slated for a specific release version.

As a possible work-around, you could add a field named "lastElement" (or equivalent) to your document, which contains a copy of the last element pushed to the array. In your update statement, you could then query against the "lastElement" value, and if it matches, simultaneously set it to the new value and push the same value to the array in a single, atomic operation.

For example:

> db.blogposts.save({_id:5, comments:[{by: "Abe", text:"First"}], lastElement:{by: "Abe", text:"First"}})
> db.blogposts.find().pretty()
{
    "_id" : 5,
    "comments" : [
        {
            "by" : "Abe",
            "text" : "First"
        }
    ],
    "lastElement" : {
        "by" : "Abe",
        "text" : "First"
    }
}
> db.blogposts.update({"lastElement.text":"First"}, {$set:{lastElement:{by: "Joe", text:"Second"}}, $push:{comments:{by: "Joe", text:"Second"}}})
> db.blogposts.find().pretty()
{
    "_id" : 5,
    "comments" : [
        {
            "by" : "Abe",
            "text" : "First"
        },
        {
            "by" : "Joe",
            "text" : "Second"
        }
    ],
    "lastElement" : {
        "by" : "Joe",
        "text" : "Second"
    }
}
> 

As an alternative, you may consider the strategy outlined in the "Update if Current" section of the "Atomic Operations" documentation: http://www.mongodb.org/display/DOCS/Atomic+Operations

I realize these are work-arounds and not ideal solutions. Hopefully the above will help you to accomplish your goal, or at least provide some food for thought for you to come up with a different solution. If you do, please share it here so that any members of the Community who may be experiencing similar issues may have the benefit of your experience. Thanks.




回答2:


Looks like as of mongoDB v2.6, this is now supported via the $position operator: http://docs.mongodb.org/manual/reference/operator/update/position/

db.blogposts.update(
  {_id:5}
  , {$push:
      {comments:
          {$each: {by: "Abe", text:"First"}
          , $position:0 }
      }
  }
);


来源:https://stackoverflow.com/questions/10094573/use-mongodb-array-as-stack

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!