0

Here is my structure : structure example

M 1 ---->
   Produits Array ----->
               0 ----->
                  ----> Id: 0
                  ----> Status : 0
                  ----> Id: 1
                  ----> Status : 0
                  ----> Id: 2
                  ----> Status : 0
               1 ----->
                  ----> Id: 3
                  ----> Status : 0
                  ----> Id: 4
                  ----> Status : 0
                  ----> Id: 5
                  ----> Status : 0
               2 ----->
                  ----> Id: 6
                  ----> Status : 0
                  ----> Id: 7
                  ----> Status : 0
                  ----> Id: 8
                  ----> Status : 0
M 2 ---->
   Produits Array ----->
               0 ----->
                  ----> Id: 9
                  ----> Status : 0
                  ----> Id: 10
                  ----> Status : 0
                  ----> Id: 11
                  ----> Status : 0

As you can see, the Produits fields in the main objects are an array of objects. Now I would like to update all Status fields of the objects inside each Produits array where the reference is 2172, 2173, etc. to the value -1

I search on internet and everything I found is some foreach methods which is not providing fast performance for a server.

I also tried with the operator $. But as described in the Mongo documentation, it's only matching the first element of an array. So it won't work if I have more than one element.

So I would like to know if someone has an good idea to update multi item's fields inside an array ?

Thanks in advance

2 Answers 2

1

This sounds like a job for $elemMatch. (I know you said you tried the positional operator, but you didn't detail how.)

So, something like this should work:

db.<some collection>.update({products:{$elemMatch:{reference:2172}}}, {$set:{'products.$.status':-1}})

Since {multi:true} won't work because each sub document is under one document, I think you have have only two options:

  1. Pull each document that matches the $elemMatch query into your
    application, edit it, and save it back.

  2. Consider moving your subdocuments to their own collection so that your update will work.

Sign up to request clarification or add additional context in comments.

5 Comments

this would update only one element in the array, even if multiple elements matched the condidtion {reference:2172}. the positional operator returns the first element matching the query criteria
@AnandJayabalan D'oh, I see. {multi:true} won't work because all of these subdocuments are under one document...
yeah but in fact, my goal is to limit the call to mongo server at only 1. I would like to do it in one query that I will launch from my .net application. I agree with your first idea. But in my example, I have two documents... When I'll use the app, I might have 1000 or 5000 documents to edit. I feel it's not so good in the point of performance to do a first request to get the documents, iterate through them and save them back to the database.
@AdrienA. I believe a cursor will still work for you. This way you are not pulling them all into the app at once. Or, you can store a custom js function in mongo. I see you have already found that solution.
yeah but it is very slow in terms of performance.... : 3 minutes for updating 1000 rows... it is not possible with this way
0

I finally find a "solution" by using a stored function :

function UpdateStatusProduits (produitsReference, status) {
    if (produitsReference.length === 0) {
        return;
    }

    produitsReference.forEach(function(reference) {
        db.Prodel.update(
            {"Produits.Reference": reference},
            { $set: { "Produits.$.Status": NumberInt(status)}}
        );
    });
}

It is working, but the performance is not so good as a query... anyway, it is one way, but it can't be consider as a final solution when there are requirements about performance. I ask anybody who find a better solution to provide it on this post.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.