【问题标题】:Delete element in MongoDB collection by index按索引删除 MongoDB 集合中的元素
【发布时间】:2020-06-21 11:56:09
【问题描述】:

我正在使用 pymongo 并且我有一个 users 集合。一个用户实例是这样的:

    user = {"Email":"user@gmail.com" , "Comments":["Good"  , "Bad" , " Very bad "] }

我正在尝试按索引删除 Comments[] 字段中的元素(例如 index = 0 delete "Good") 我将索引与输入编号相同的注释设置为“已删除”,然后将其拉出 但是,由于我正在为特定用户迭代 Comments[] 数组,我得到了错误

pymongo.errors.WriteError: Cannot create field 'i+1' in element

我不明白为什么。 我的代码:


                comment_num = int(comment_num) #an index I have as input
                exists = False #we will check if index exists in list 
                for i , value in enumerate(usr['Comments']):
                    if i+1 == comment_num: #if index is comment_num
                        print("Comment number exists")
                        exists = True
                        #I get the error here
                        users.update_one({"Email":email} , {"$set" : {"Comments.i+1" : "deleted" } } )
                        users.update_one({"Email":email} , {"$pull":{"Comments":"deleted" }})
                    elif i+1 == len(usr['Comments']) and exists == False:
                        print('Comment does not exist') #if index not found 

感谢您帮助指导我解决此错误。提前谢谢你

【问题讨论】:

    标签: python mongodb pymongo


    【解决方案1】:

    从 MongoDB v4.2 开始,您不能使用 $set 直接定位给定索引处的数组,也不能使用 $pull 删除给定索引处的元素。

    从 v4.2 开始,您可以使用 update with aggregation pipeline 将数组更新为指定索引之前和之后的数组元素的串联。

    因此,如果您有 i = 0,那么它将是 [] 和 ["Bad" , " Very bad "] 的串联

    如果您有i = 1,那么它将是["Good"] 和[" Very bad "] 的串联

    我们可以使用$concatArrays和$slice

    users.update_one(
      { "Email": email } , 
      [{ // specify update as an array to use the pipeline update
        "$set": {
          "Comments": {
            "$concatArrays": [
              { "$slice": ["$Comments", i] }, // keep i elements from the start of the array
              { "$slice": ["$Comments", i+1, { "$size": "$Comments" } ] } // keep element from i+1 to the end of the array
            ]
          }
        }
      }]
    )
    
    

    提示:如果要删除 first 或 last 数组元素,可以使用$pop

    【讨论】:

    • 是的,但我怎样才能让我的数组在删除后恢复到正常状态?
    • 您的意思是要找回已删除的元素?
    • 不,我的数组格式正常。前任 。 "Comments" : ["good" , "bad"] 而不是 "Comments": "concatArrays":[...]
    • 格式应该一样,只去掉一个数组元素
    • $concatArrays 是一个组合数组的运算符
    【解决方案2】:

    已修复:比我想象的要容易得多,也不那么复杂。

                comment_num = int(comment_num)
                exists = False
                for i , value in enumerate(usr['Comments']):
                    if i+1 == comment_num:
                        print("Comment number exists")
                        exists = True
                        users.update_one({"Email":email} , 
                        {"$pull":{"Comments":value}})
                    elif i+1 == len(usr['Comments']) and exists == False:
                        print('Comment does not exist')
    

    【讨论】:

    • 您的解决方案不考虑重复值。它可能适用于您的用例,但不适用于一般用例。如果你有 ["Good", "Bad", "Very Bad", "Good"] 并且想要删除索引 3 处的 "Good" 怎么办?
    • @thammada.ts 我希望它完全适用于特定值
    • 那么如果相同的值出现两次,你是否也想删除这两个元素?在这种情况下,您可以使用$pullAll
    • @thammada.ts 不,我有一个 cmets 列表,我的 cmets 编号从 1 到 .. 最后一条评论,我输入一个数字作为输入。那么对应数字的评论就被删除了
    • 好的,你的意思仍然是在特定索引处。您当前的解决方案没有考虑到这一点,并将删除包含相同值的第一个元素
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 2013-09-10
    • 2017-12-16
    • 1970-01-01
    • 2020-01-02
    • 2021-02-14
    相关资源
    最近更新 更多