Annex Collections

An annex collection is a collection that includes an extension to documents in another collection. An annex collection is an extension of a real collection, which in this context we call a “base collection”

Every line in the annex collection will have an _id field which represents the internal id of a document in the base collection.

This _id field allows you to easily reference the annex collection fields and allows the user to view the annex collection as an extension on the base collection.

Example of a valid annex:

Base collection:
> db.session.find()
{"Session Id": 1, "Session Start": ISODate("2017-01-01T00:00:00.000")}
{"Session Id": 2, "Session Start": ISODate("2017-01-01T01:00:00.000")}
{"Session Id": 3, "Session Start": ISODate("2017-01-01T02:00:00.000")}

Annex collection:
> db.LMRM__ANNEX__session__LMRM__annex_session_end.find()
{"_id": NumberLong("4611686018427387904"), "Session End": ISODate("2017-01-02T00:00:00.000")}
{"_id": NumberLong("4611686018427387905"), "Session End": ISODate("2017-01-01T03:00:00.000")}
{"_id": NumberLong("4611686018427387906"), "Session End": ISODate("2017-01-01T02:01:00.000")}

Querying while using the annex collection to get the session length:

> pipeline = [
{
    "$project" : {
        "_id" : 0,
        "Session Id" : 1,
        "Session Length MS" : {
            "$subtract" : [
                "$__annexed.$annex_session_end.$Session End",
                "$Session Start"
            ]
        }
    }
}]
> db.session.aggregate(pipeline)
{"Session Id": 1, "Session Length MS": NumberLong(86400000)}
{"Session Id": 2, "Session Length MS": NumberLong(7200000)}
{"Session Id": 3, "Session Length MS": NumberLong(60000)}

An annex collection’s name is always has this structure:

LMRM__ANNEX__<base collection name>__LMRM__<annex name>

in the example above the base collection name is session and annex name is annex_session_end

Creating an annex

An annex collection is created using a pipeline that generated the requested annex and then produces it with an annex $out stage

Generally this pipeline will run on the base collection and will start with a $project that produced the rdid on the _id field

Syntax:

{$out: {$annex: <annex name>}}

Usage:

> db.base.find()
{ "_id" : ObjectId("5abacb3abee7b2efe770dcc4"), "a" : 1, "b" : 1 }
{ "_id" : ObjectId("5abacb3abee7b2efe770dcc5"), "a" : 1, "b" : 2 }
{ "_id" : ObjectId("5abacb3abee7b2efe770dcc6"), "a" : 2, "b" : 3 }
{ "_id" : ObjectId("5abacb3abee7b2efe770dcc7"), "a" : 2, "b" : 4 }


> pipeline = [
    {
        "$project" : {
            "_id" : {
                "$did" : 2
            },
            "c" : {
                "$add" : [
                    "$a",
                    "$b"
                ]
            }
        }
    },
    {
        "$out" : {
            "$annex" : "annex_c"
        }
    }
]

> db.base.aggregate({$project: {_id:{$did: 2}, "c": {$add:["$a", "$b"]}}}, {$out: {$annex:"annex_c"}})

This query will generate and annex collection that looks like this:

> db.LMRM__ANNEX__base__LMRM__annex_c.find()
{ "_id" : NumberLong("4611686018427387904"), "c" : 2 }
{ "_id" : NumberLong("4611686018427387905"), "c" : 3 }
{ "_id" : NumberLong("4611686018427387906"), "c" : 5 }
{ "_id" : NumberLong("4611686018427387907"), "c" : 6 }

Querying an annex

Querying an annex can be done anywhere you can input an expression (similar to a projection expression). There are two ways of querying an annex collection, one is similar to a $ field reference, and the other is in classic expression style

If the expression evaluates to a single field of the annex collection, then the value of the expression will be the value of the field. If the expression evaluates to multiple fields in the annex collection then the value will be a document containing all the annex fields

Syntax:

{$annexed: {collection: <annexed name>, fields/field: <field name/array/*>}}

"$__annexed.$<annex name>.$<field name>/*"

Usage using $ field reference:

> pipeline = [
{
    "$project" : {
        "_id" : 0,
        "Session Id" : 1,
        "Session Length MS" : {
            "$subtract" : [
                "$__annexed.$annex_session_end.$Session End",
                "$Session Start"
            ]
        }
    }
}]
> db.session.aggregate(pipeline)
{"Session Id": 1, "Session Length MS": NumberLong(86400000)}
{"Session Id": 2, "Session Length MS": NumberLong(7200000)}
{"Session Id": 3, "Session Length MS": NumberLong(60000)}

> pipeline = [
{
    "$project" : {
        "_id" : 0,
        "Session Id" : 1,
        "Session Length MS" : {
            "$subtract" : [
                {
                    "$annexed": {
                        "collection": "annex_session_end",
                        "field": "Session End"
                    }
                }
                "$__annexed.$annex_session_end.$Session End",
                "$Session Start"
            ]
        }
    }
}]
> db.session.aggregate(pipeline)
{"Session Id": 1, "Session Length MS": NumberLong(86400000)}
{"Session Id": 2, "Session Length MS": NumberLong(7200000)}
{"Session Id": 3, "Session Length MS": NumberLong(60000)}

Usage using classic expression language:

> pipeline = [
{
    "$project" : {
        "_id" : 0,
        "Session Id" : 1,
        "Session Length MS" : {
            "$subtract" : [
                {
                    "$annexed": {
                        "collection": "annex_session_end",
                        "field": "Session End"
                    }
                }
                "$Session Start"
            ]
        }
    }
}]
> db.session.aggregate(pipeline)
{"Session Id": 1, "Session Length MS": NumberLong(86400000)}
{"Session Id": 2, "Session Length MS": NumberLong(7200000)}
{"Session Id": 3, "Session Length MS": NumberLong(60000)}

Usage using “*” fields and displaying multiple annex fields in a subdocument:

> pipeline = [
{
    "$project" : {
        "_id" : 0,
        "Session Id" : 1,
        "Session end annex fields" : {
                "$annexed": {
                    "collection": "annex_session_end",
                    "field": "*"
                }
            }
        }
    }
}]
> db.session.aggregate(pipeline).pretty()
{
    "Session Id" : 1,
    "Session end annex fields" : {
        "_id" : NumberLong("4611686018427387904"),
        "Session End" : ISODate("2017-01-02T00:00:00Z")
    }
}
{
    "Session Id" : 2,
    "Session end annex fields" : {
        "_id" : NumberLong("4611686018427387905"),
        "Session End" : ISODate("2017-01-01T03:00:00Z")
    }
}
{
    "Session Id" : 3,
    "Session end annex fields" : {
        "_id" : NumberLong("4611686018427387906"),
        "Session End" : ISODate("2017-01-01T02:01:00Z")
    }
}

Note

Querying an annex can be done in a $match or a find using the $expr modifier.