M220P Lookup Ticket

Being new to Python, I am having a terrible time with scope… I am used to using the { } to track my scope but with python using indentation also, I get closing errors when I write code on multiple lines…

In doing the ticket, I get errors telling me the brackets and such are not closed.

Can I get some tips on the best way to correct this issue?

At first sight it looks like you are missing a closing brace at line 271 to match the first opening one.

1 Like

Thanks… I figured it out… I think…

My error was that I needed to enclose the from, let, pipeline, and as in " " s. By doing this it cleared up the brackets and brace errors.

However, when I run the pytest on get_comments both tests fail… SO… Can someone point me in the right direction on what my error is?

        pipeline = [
            {
                "$match": {
                    "_id": ObjectId(id)
                }
                
            },
            {
                "$lookup": 
                    {
                        "from": "comments", 
                        "let" : {"id": "$_id"},
                        "pipeline": [
                            { "$match":
                                {"$expr": {"$eq": ["movie_id", "$$id"]}}
                        }
                        ],
                        "as": "comments"
                    }
            }
        ]

I believe I have structured this correctly… (hence the reason for this response…LOL)

The get_movie takes in the id.

It then matches the _id to the ObjectId(id)

So… to implement the lookup stage I should just have to add a lookup stage to the end of the match stage using a , and another { } with the “$lookup”: inside the { }

Inside the lookup stage I use the from stage to id the comments collection
I let “$id” equal “_id”
then I use the pipeline stage to make an expr to compaire “movie_id” field in the comments collection to the “$$id” variable ( the “_id” in the object).
I then put the results of this query into the comments using “as”

Is this rational correct?

Yes. That’s true. Python is not like JS and needs fields name in quotes.

I also see that you added the missing closing braces.

If I remember correctly, in all M220 courses, the requirements include having to sort the comments by date descending.

@steevej,
You are correct… I forgot to add the sort portion…

I changed from the new lookup process and I went back to the old format and. it worked… For some reason I either don’t understand the let process combined with the pipeline, or my cluster that mflix is running on isn’t updated to use the new process.

So… Now 1 fails and 2 pass… Here is my output.

client = <FlaskClient <Flask 'mflix.factory'>>

    @pytest.mark.get_comments
    def test_comments_should_be_sorted_by_date(client):
        # in order from most to least recent
        movie_ids = [
            "573a1391f29313caabcd8414",
            "573a1392f29313caabcd9d4f",
            "573a1392f29313caabcdae3d",
            "573a1392f29313caabcdb40b",
            "573a1392f29313caabcdb585",
            "573a1393f29313caabcdbe7c",
            "573a1393f29313caabcdd6aa"
        ]
        for id in movie_ids:
            comments = get_movie(id).get('comments', [])
            test_comments = sorted(
                comments[:],
                key=lambda c: c.get('date'),
                reverse=True
            )
            for _ in range(0, min(10, len(comments))):
                rand_int = randint(0, len(comments) - 1)
>               assert comments[rand_int] == test_comments[rand_int]
E               AssertionError: assert {'_id': Objec...cdbe7c'), ...} == {'_id': Object...cdbe7c'), ...}
E                 Omitting 1 identical items, use -vv to show
E                 Differing items:
E                 {'name': 'Daniel Simmons'} != {'name': 'Kelsey Smith'}
E                 {'date': datetime.datetime(1982, 11, 20, 12, 45, 24)} != {'date': datetime.datetime(1998, 11, 13, 19, 17, 59)}
E                 {'_id': ObjectId('5a9427648b0beebeb6958238')} != {'_id': ObjectId('5a9427648b0beebeb69582a8')}
E                 {'email': 'daniel_simmons@fakegmail.com'} != {'email': 'kelsey_smith@fakegmail.com'}
E                 {'text': 'Magni error rerum dolorem optio. Id expedita provident nam corporis dicta itaque odit. Est recusandae sed unde id fuga.'} != {'text': 'Iure dolor id pariatur non su...
E                 
E                 ...Full output truncated (2 lines hidden), use '-vv' to show

tests/test_get_comments.py:49: AssertionError
===================================== 40 tests deselected ======================================
====================== 1 failed, 2 passed, 40 deselected in 0.71 seconds =======================
(mflix) bossmandave@Davids-MacBook-Pro-2 mflix-python % 

Don’t know what this test is for… Maybe duplicate entries? No Idea how to correct this.

On another note… If the lookup works. under the old format, how do I verify if I can use the new let format? When I go to atlas, there is no let option in the query builder.

OK… I don’t want to confuse anyone with asking too many questions on the same ticket… But I have noticed something that I really don’t understand.

My atlas cluster is running 5.0.6 and when I use the query builder in atlas, there are differences.

The $lookup stage still has the from, foriegnField, localField, and as structure.
I can build the query using this syntax and when I put this in the get_movie(id) method 2 of the three tests pass.
this is the code I insert:

        pipeline = [
            {
                '$match': {
                    '_id': ObjectId(id)
                }
            }, {
                '$lookup': {
                    'from': 'comments',
                    'localField': '_id',
                    'foreignField': 'movie_id',
                    'as': 'comments'
                }
            }, {
                '$sort': {'date': -1}
            }
        ]

This give the following output.


(mflix) bossmandave@Davids-MacBook-Pro-2 mflix-python % pytest -m get_comments
============================================== test session starts ==============================================
platform darwin -- Python 3.8.12, pytest-3.3.0, py-1.8.0, pluggy-0.6.0
rootdir: /Users/bossmandave/Desktop/mflix-python, inifile: pytest.ini
plugins: flask-0.11.0
collected 43 items                                                                                              

tests/test_get_comments.py ..F                                                                            [100%]

=================================================== FAILURES ====================================================
____________________________________ test_comments_should_be_sorted_by_date _____________________________________

client = <FlaskClient <Flask 'mflix.factory'>>

    @pytest.mark.get_comments
    def test_comments_should_be_sorted_by_date(client):
        # in order from most to least recent
        movie_ids = [
            "573a1391f29313caabcd8414",
            "573a1392f29313caabcd9d4f",
            "573a1392f29313caabcdae3d",
            "573a1392f29313caabcdb40b",
            "573a1392f29313caabcdb585",
            "573a1393f29313caabcdbe7c",
            "573a1393f29313caabcdd6aa"
        ]
        for id in movie_ids:
            comments = get_movie(id).get('comments', [])
            test_comments = sorted(
                comments[:],
                key=lambda c: c.get('date'),
                reverse=True
            )
            for _ in range(0, min(10, len(comments))):
                rand_int = randint(0, len(comments) - 1)
>               assert comments[rand_int] == test_comments[rand_int]
E               AssertionError: assert {'_id': Objec...cdbe7c'), ...} == {'_id': Object...cdbe7c'), ...}
E                 Omitting 1 identical items, use -vv to show
E                 Differing items:
E                 {'date': datetime.datetime(1999, 7, 11, 4, 8, 32)} != {'date': datetime.datetime(2007, 11, 4, 10, 12, 40)}
E                 {'email': 'joshua_kent@fakegmail.com'} != {'email': 'theresa_holmes@fakegmail.com'}
E                 {'_id': ObjectId('5a9427648b0beebeb695829c')} != {'_id': ObjectId('5a9427648b0beebeb6958340')}
E                 {'name': 'Joshua Kent'} != {'name': 'Theresa Holmes'}
E                 {'text': 'Aliquam cupiditate possimus impedit ab. Dolor neque eos est sunt nesciunt odit. Numquam mollitia est provident sunt doloribus. Totam magni quam ducimus.'} != {'text': 'Of...
E                 
E                 ...Full output truncated (2 lines hidden), use '-vv' to show

tests/test_get_comments.py:49: AssertionError
============================================== 40 tests deselected ==============================================
=============================== 1 failed, 2 passed, 40 deselected in 0.73 seconds ===============================
(mflix) bossmandave@Davids-MacBook-Pro-2 mflix-python % 

Now when I change the query in the query builder to use the let stage, I get an output in atlas.
This is the query that works in atlas…(I had to replace id with a specific id)

[
            {
                '$match': {
                    '_id': ObjectId(id)
                }
            }, {
                '$lookup': {
                    'from': 'comments',
                    'let': {'id': '$_id'},
                    'pipeline': [
                        {
                            '$match': {
                                '$expr': {'$eq': ['movie_id', '$$id']}
                            }
                        }
                    ],
                'as': 'comments'
                }
            }, {
                '$sort': {
                    'date': -1
                }
            }
        ]

but when I run this in the program 2 of the three tests fail. This is the output from running pytest -m get_comnments with the new lookup.

(mflix) bossmandave@Davids-MacBook-Pro-2 mflix-python % pytest -m get_comments
============================================== test session starts ==============================================
platform darwin -- Python 3.8.12, pytest-3.3.0, py-1.8.0, pluggy-0.6.0
rootdir: /Users/bossmandave/Desktop/mflix-python, inifile: pytest.ini
plugins: flask-0.11.0
collected 43 items                                                                                              

tests/test_get_comments.py FF.                                                                            [100%]

=================================================== FAILURES ====================================================
_________________________________________ test_fetch_comments_for_movie _________________________________________

client = <FlaskClient <Flask 'mflix.factory'>>

    @pytest.mark.get_comments
    def test_fetch_comments_for_movie(client):
        # Lady and the Tramp
        movie_id = "573a1394f29313caabcdfd61"
        result = get_movie(movie_id)
>       assert len(result.get('comments', [])) == 126
E       AssertionError: assert 0 == 126
E        +  where 0 = len([])
E        +    where [] = <built-in method get of dict object at 0x10e961c00>('comments', [])
E        +      where <built-in method get of dict object at 0x10e961c00> = {'_id': ObjectId('573a1394f29313caabcdfd61'), 'awards': {'nominations': 1, 'text': 'Nominated for 1 BAFTA Film Award. ...1 nomination.', 'wins': 2}, 'cast': ['Peggy Lee', 'Larry Roberts', 'Bill Baucom', 'Verna Felton'], 'comments': [], ...}.get

tests/test_get_comments.py:17: AssertionError
_____________________________________ test_fetch_comments_for_another_movie _____________________________________

client = <FlaskClient <Flask 'mflix.factory'>>

    @pytest.mark.get_comments
    def test_fetch_comments_for_another_movie(client):
        # 300
        movie_id = "573a13b1f29313caabd36321"
        result = get_movie(movie_id)
>       assert len(result.get('comments', [])) == 145
E       AssertionError: assert 0 == 145
E        +  where 0 = len([])
E        +    where [] = <built-in method get of dict object at 0x10e9e0f40>('comments', [])
E        +      where <built-in method get of dict object at 0x10e9e0f40> = {'_id': ObjectId('573a13b1f29313caabd36321'), 'awards': {'nominations': 37, 'text': '19 wins & 37 nominations.', 'wins': 19}, 'cast': ['Gerard Butler', 'Lena Headey', 'Dominic West', 'David Wenham'], 'comments': [], ...}.get

tests/test_get_comments.py:25: AssertionError
============================================== 40 tests deselected ==============================================
=============================== 2 failed, 1 passed, 40 deselected in 0.82 seconds ===============================

Not sure why this happens… If the query works using both methods… why does one pass more tests than the other?

Your $sort is wrong.

You are sorting the single movie out of the top most pipeline. You need to sort the comments.

@steevej ,
Thanks… I have built the query in atlas, and it works with one of the Object ids that is in the test, but in atlas, it brings up an empty array… Here is the querry:

[{$match: {
  _id: ObjectId('573a1393f29313caabcdbe7c')
}}, {$lookup: {
  from: 'comments',
  let: {'id': '$_id'},
  pipeline:[
    {'$match':
      {'$expr': {'$eq': ['movie_id', '$$id']}}
    },
    {
      '$sort': {'date': -1}
    }
    ],
    as: 'comments'
}}]

That is the pipeline… In Python it is:

[
    {
        '$match': {
            '_id': ObjectId('573a1393f29313caabcdbe7c')
        }
    }, {
        '$lookup': {
            'from': 'comments', 
            'let': {
                'id': '$_id'
            }, 
            'pipeline': [
                {
                    '$match': {
                        '$expr': {
                            '$eq': [
                                'movie_id', '$$id'
                            ]
                        }
                    }
                }, {
                    '$sort': {
                        'date': -1
                    }
                }
            ], 
            'as': 'comments'
        }
    }
]

It runs in the program… But it fails the tests… I have double and triple checked it… Can you see what I am doing wrong?

To make it run in the program, I just take out the object id and place it with the variable.

Inside $expr field names must be preceded with $.

Thanks… Here is my issue… If I use the old lookup version, I can get the first two tests to pass but not the third… When I change the lookup to the version with the pipeline, I can get the last test to pass but the array fails… Here is my code…

I am stumped as to why the first two fail… I am passing in the id (Which is the Object ID (_Id from the movie array). then I am using that to assign it to the 'id field… Don’t understand why the two tests that test the number of comments in the array fail, but the random sort passes.

Any Ideas?

I corrected the error in ‘eq’ : It is now ‘$eq’ : But the query still fails… It isn’t loading the array… but the third test which takes a random sample of the array passes… Not sure I understand why this is happening.

LOL. I also found the error in ‘_id’. It is now ‘$_id’.

-----------UPDATE------------

Thanks for all your help… I figured it out… I was messing up with the $ operator in multiple places… Thanks for your patience with me.

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.