Search code examples
mongodbgoprojectionmgodatabase

MongoDB (Mgo v2) Projection returns parent struct


I have here a Building Object where inside sits an Array of Floor Objects.

When Projecting, my goal is to return or count the number of Floor Objects inside a Building Object after matching the elements accordingly. The code is as follows:

Objects:

type Floor struct {
    // Binary JSON Identity
    ID bson.ObjectId `bson:"_id,omitempty"`
    // App-level Identity
    FloorUUID string `bson:"f"`
    // Floor Info
    FloorNumber int `bson:"l"`
    // Units
    FloorUnits []string `bson:"u"`
    // Statistics
    Created time.Time `bson:"y"`
}

type Building struct {
    // Binary JSON Identity
    ID bson.ObjectId `bson:"_id,omitempty"`
    // App-level Identity
    BldgUUID string `bson:"b"`
    // Address Info
    BldgNumber  string `bson:"i"` // Street Number
    BldgStreet  string `bson:"s"` // Street
    BldgCity    string `bson:"c"` // City
    BldgState   string `bson:"t"` // State
    BldgCountry string `bson:"x"` // Country
    // Building Info
    BldgName      string `bson:"w"`
    BldgOwner     string `bson:"o"`
    BldgMaxTenant int    `bson:"m"`
    BldgNumTenant int    `bson:"n"`
    // Floors
    BldgFloors []Floor `bson:"p"`
    // Statistics
    Created time.Time `bson:"z"`
}

Code:

func InsertFloor(database *mgo.Database, bldg_uuid string, fnum int) error {

    fmt.Println(bldg_uuid)
    fmt.Println(fnum) // Floor Number

    var result Floor // result := Floor{}

    database.C("buildings").Find(bson.M{"b": bldg_uuid}).Select(
        bson.M{"p": bson.M{"$elemMatch": bson.M{"l": fnum}}}).One(&result)

    fmt.Printf("AHA %s", result)
    return errors.New("x")
}

It turns out, no matter how I try the query returns a Building Object, not a floor object? What changes do I need to make in order to have the query fetch and count Floors and not Buildings?

This is done so to check if a Floor inside Building already exists before insertion. If there's a better a approach then I'll replace mine with the better!

Thanks!


Solution

  • You are querying for a Building document so mongo returns that to you even though you try to mask some of its fields using projection.

    I don't know of a way to count the number of elements in a mongo array in a find query, but you can use the aggregation framework, where you have the $size operator that does exactly this. So you should send a query like this to mongo :

    db.buildings.aggregate([
    {
        "$match":
        {
            "_id": buildingID,
            "p": {
                 "$elemMatch": {"l": fNum}
             }
        }
    },
    {
        "$project":
        {
            nrOfFloors: {
                "$size": "$p"
            }
        }
    }])
    

    Which in go it would look like

    result := []bson.M{}
    match := bson.M{"$match": bson.M{"b": bldg_uuid, "p": bson.M{"$elemMatch": bson.M{"l": fNum}}}}
    count := bson.M{"$project": bson.M{"nrOfFloors": bson.M{"$size": "$p"}}}
    operations := []bson.M{match, count}
    pipe := sess.DB("mgodb").C("building").Pipe(operations) 
    pipe.All(&result)