Search code examples
node.jsmongodbmongoosemongoose-schemamongoose-populate

simple join SQL like with mongoose


I have documents and parameters and I'm trying to build a query to select the documents matching the parameters.

document {
_id : ...,
status : ...,
type : ...,
...
}
parameter {
_id : ...,
parameter : ...,
status : ...,
type : ...,
}

I do think SQL it kills me. How do I do :

select document.* from document,parameter 
  where document.type = parameter.type and document.status = parameter.status
         and parameter.parameter="example"

I might not have think is the proper way ex : i don't use the any reference link between both objects, I might but it would be an N to N link and I don't feel like it would be easy to maintain as parameter or document would be updated.


Solution

  • Please try below query :

    db.document.aggregate([
       {
          $lookup:
             {
               from: "parameter",
               let: { type: "$type", status: "$status" },
               pipeline: [
                  { $match:
                     { $expr:
                        { $and:
                           [
                             { $eq: [ "$parameter",  "example" ] },
                             { $eq: [ "$type",  "$$type" ] },
                             { $eq: [ "$status", "$$status" ] }
                           ]
                        }
                     }
                  }
               ],
               as: "documentParameterJoined"
             }
        }
    ])
    

    Document Collection Data :

    /* 1 */
    {
        "_id" : ObjectId("5e160929627ef782360f69aa"),
        "status" : "mystatus",
        "type" : "whattype"
    }
    
    /* 2 */
    {
        "_id" : ObjectId("5e160931627ef782360f6abb"),
        "status" : "mystatus1",
        "type" : "whattype1"
    }
    

    Parameter Collection Data :

    /* 1 */
    {
        "_id" : ObjectId("5e16095f627ef782360f6e1d"),
        "parameter" : "example",
        "status" : "mystatus",
        "type" : "whattype"
    }
    
    /* 2 */
    {
        "_id" : ObjectId("5e16097e627ef782360f70b5"),
        "parameter" : "example",
        "status" : "mystatus1",
        "type" : "whattype1"
    }
    
    /* 3 */
    {
        "_id" : ObjectId("5e160985627ef782360f7152"),
        "parameter" : "example1",
        "status" : "mystatus",
        "type" : "whatType"
    }
    
    /* 4 */
    {
        "_id" : ObjectId("5e160a39627ef782360f8027"),
        "parameter" : "example",
        "status" : "mystatus1",
        "type" : "whatType"
    }
    
    /* 5 */
    {
        "_id" : ObjectId("5e160a42627ef782360f80ec"),
        "parameter" : "example",
        "status" : "mystatus",
        "type" : "whatType1"
    }
    

    Result :

     // You don't see docs 3 to 5 as they don't match any filter criteria.
    /* 1 */
    {
        "_id" : ObjectId("5e160929627ef782360f69aa"),
        "status" : "mystatus",
        "type" : "whattype",
        "documentParameterJoined" : [ 
            {
                "_id" : ObjectId("5e16095f627ef782360f6e1d"),
                "parameter" : "example",
                "status" : "mystatus",
                "type" : "whattype"
            }
        ]
    }
    
    /* 2 */
    {
        "_id" : ObjectId("5e160931627ef782360f6abb"),
        "status" : "mystatus1",
        "type" : "whattype1",
        "documentParameterJoined" : [ 
            {
                "_id" : ObjectId("5e16097e627ef782360f70b5"),
                "parameter" : "example",
                "status" : "mystatus1",
                "type" : "whattype1"
            }
        ]
    }
    

    You don't need to do two db calls, you can use $lookup (which is native to mongoDB) with expression to achieve what's needed. Also you can try similar using mongoose populate (which is a kind of wrapper to mongoDB $lookup)

    Ref : $lookup , mongoose-populate