Teito
Teito

Reputation: 13

How to $concat two fields inside a subdocument in mongodb

WHAT I WANT TO ACHIEVE

Let us say I have this object:

{
    "_id" : ObjectId("5aec063380a7490014e88792"),
    "personal_info" : {
        "dialing_code": "+44",
        "phone_number": "67467885664"
    }
}

I need to concat the two values personal_info.dialing_code (+44) and phone_number (67467885664) into one. +4467467885664 and compare it to a value. I need to retrieve a specific record from the database that will match the said value.

PROBLEM

I am having trouble concatinating two fields inside a subdocument and I am receiving this error:

{
    "name": "MongoError",
    "message": "$concat only supports strings, not object",
    "ok": 0,
    "errmsg": "$concat only supports strings, not object",
    "code": 16702,
    "codeName": "Location16702"
}

ATTEMPT #1

I have tried this:

UserModel.aggregate([
        { $unwind: '$personal_info' },
        {$project: {
            concat_p: {$concat: [
                '$personal_info.dialing_code',
                '$personal_info.phone_number'
            ]} 
        }}
    ])

It is giving me an error as mentioned above and in result I cannot do a $match right after.

ATTEMPT #2

I also tried this:

UserModel.aggregate([
        { $unwind: '$personal_info' },
        {$project: {
            p_dialing_code: '$personal_info.dialing_code',
            p_phone_number: '$personal_info.phone_number',
            concat_p: {$concat: [
                '$p_dialing_code',
                '$p_phone_number'
            ]} 
        }}
    ])

I have successfully took out the subdocument values one level however when I tried concatinating, it is producing me null values. This is the result I am getting:

{
        "_id": "5af0998036daa90014129d6e",
        "p_dialing_code": "+44",
        "p_phone_number": "13231213213244",
        "concat_p": null
    }

I know how to do it on the $match pipeline but I have no luck concatinating the values inside the subdocument. Clearly, I need to do this first before I can compare. Thanks

Upvotes: 0

Views: 1719

Answers (1)

mickl
mickl

Reputation: 49975

It seems like you have different types under personal_info.dialing_code and personal_info.phone_number fields. In your example $concat is applied to every document in your collection and that's why you're getting an exception since $concat strictly expects its parameters to be strings.

So it will be working fine for document posted in your question but will throw an exception for something like this:

{
    "_id" : ObjectId("5aec063380a7490014e88792"),
    "personal_info" : {
        "dialing_code": {},
        "phone_number": "67467885664"
    }
}

One way to fix this is to add $match condition before $project and use $type operator to get only documents having strings on those fields you want to concatenate.

db.UserModel.aggregate([
    {
        $match: {
            $expr: {
                $and: [
                    { $eq: [ { $type: "$personal_info.dialing_code" }, "string" ] },
                    { $eq: [ { $type: "$personal_info.phone_number" }, "string" ] }
                ]
            }
        }
    },
    {$project: {
        concat_p: {$concat: [
            "$personal_info.dialing_code",
            "$personal_info.phone_number"
        ]} 
    }}
])

Upvotes: 1

Related Questions