1

I have the following sample document saved in my mongodb collection :

   {
       _id:"3213dsadsa812321",
       files: [ 
       {_id: "99300", path:"C:\Filename01.txt"},
       {_id: "99301", path:"C:\Filename02.txt"},
       {_id: "99302", path:"C:\Filename03.txt"},
       {_id: "99303", path:"C:\Filename04.txt"},
       ]
   }

and I have the following array var dynFiles:

  [          
       {_id: "1", path:"C:\folder\textfile01.txt"},
       {_id: "2", path:"C:\folder\textfile02.txt"},
       {_id: "3", path:"C:\folder\textfile03.txt"},
       {_id: "4", path:"C:\Filename04.txt"},
  ]

is it possible to find if any of the mongodb document objects array path key match any of the dynFiles var path key?

In other words, based on the given above record _id: "99303" in db should be returned as it match the var object array _id: "4".

Expected result:

[ {_id: "99303", path:"C:\Filename04.txt"} ]

After extensive research I wrote the following query but unfortunately it doesn't help much as it compare the document files.path keys with a specific object array key, while I need it to compare files.path with all paths of dynFiles. Thanks in advance for your help and time

{ 'files.path': {$eq: dynFiles.path} }

2 Answers 2

0

You would require another array that contains just the mapped paths and this can be derived using JavaScript's .map() method. This array will then be used in the mongo query as the $in operator value. The following demonstrates this:

var dynFiles = [          
       {_id: "1", path:"C:\folder\textfile01.txt"},
       {_id: "2", path:"C:\folder\textfile02.txt"},
       {_id: "3", path:"C:\folder\textfile03.txt"},
       {_id: "4", path:"C:\Filename04.txt"},
    ],
    paths = dynFiles.map(function(f){ return f.path; });

db.collection.find({"files.path": {"$in": paths }})
Sign up to request clarification or add additional context in comments.

Comments

0

Using the .aggregate() method.

First you need to return an array of "path" using the .map() method.

> var dynFiles = [          
...        {_id: "1", path:"C:\folder\textfile01.txt"},
...        {_id: "2", path:"C:\folder\textfile02.txt"},
...        {_id: "3", path:"C:\folder\textfile03.txt"},
...        {_id: "4", path:"C:\Filename04.txt"},
...   ];
> var paths = dynFiles.map(function(element) {
... return element.path;
... });
> paths
[
        "C:\folder\textfile01.txt",
        "C:\folder\textfile02.txt",
        "C:\folder\textfile03.txt",
        "C:Filename04.txt"
]

Then comes the aggregation query:

You only need one stage in your pipeline which is the $project stage where you use the $map operator to return an array of sub-documents that where "path" is in "dynFiles". To check if a given "path" is in "dynFiles" you use the $setIsSubset operator in $cond expression. The reason you need the $setIsSubset is because you can't use the $in operator in $cond expression. Of course the $setIsSubset operator takes two arrays as parameter you need to use the $map operator to return one element array. Of course the $literal operator let you assign a literal array to the "input" in $map. Also you need to use the $setDifference here to filter out all false from the array which is fine as long as the data being filtered is "unique".

db.paths.aggregate([
    { "$project": { 
        "files": { 
            "$setDifference": [
                { "$map": { 
                    "input": "$files", 
                    "as": "file", 
                    "in": { 
                        "$cond": [ 
                            { "$setIsSubset": [ 
                                { "$map": {
                                    "input": { "$literal": [ "A" ] },
                                    "as": "el", 
                                    "in": "$$file.path"
                                }}, 
                                paths
                            ] },
                            "$$file",
                            false 
                        ]
                    }
                }}, 
                [false]
            ]
        }
    }}
])

Another way and probably the easiest way is by using the $filter operator new in MongoDB 3.2

db.paths.aggregate([
    { "$project": { 
        "files": {
            "$filter": { 
                "input": "$files", 
                "as": "file",  
                "cond": {
                    "$setIsSubset": [
                        { "$map": {
                            "input": { "$literal": [ "A" ] }, 
                            "as": "el", 
                            "in": "$$file.path"
                        }}, 
                        paths 
                    ]
                }
            }
        }
    }}
])

Both queries yield the same result:

{
        "_id" : "3213dsadsa812321",
        "files" : [
                {
                        "_id" : "99303",
                        "path" : "C:Filename04.txt"
                }
        ]
}

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.