Unhashable type: 'list' when using push in pymongo

Viewed 70

I am currently working on a web scraping project. The goal is to retrieve the price of the different types of fuel available in the gaz stations (900+) each day . If the price changes, the script will be able to append the new price to my Mongodb database.

The data collected looks like this:

Price_post_api = {

    "station_id": 31200009,
    "price_detail": [
      {
        "fuel_id": 1,
        "fuel_name": "Gazole",
        "fuel_cost": 1.959,
        "update_date": {
          "$date": "2022-05-30T10:05:22Z"
        }
      },
      {
        "fuel_id": 2,
        "fuel_name": "SP95",
        "fuel_cost": 2.049,
        "update_date": {
          "$date": "2022-05-30T10:05:23Z"
        }
      },
      {
        "fuel_id": 5,
        "fuel_name": "E10",
        "fuel_cost": 2.009,
        "update_date": {
          "$date": "2022-05-30T10:05:23Z"
        }
      }
    ]
  },

I'm having a hard time to figure out how to $push properly the data in Mongodb based on the "fuel_cost" field. Here an example of the expected output in the db.

Mongodb_price_data ={
    "station_id": 31200009,
    "price_detail": [
      {
        "fuel_id": 1,
        "fuel_name": "Gazole",
        "fuel_cost": 1.959,
        "update_date": {
          "$date": "2022-05-30T10:05:22Z"
        }
      },
      {
        "fuel_id": 1,
        "fuel_name": "Gazole",
        "fuel_cost": 35.87,
        "update_date": {
          "$date": "2022-05-31T10:09:22Z"
        }
      },
      {
        "fuel_id": 2,
        "fuel_name": "SP95",
        "fuel_cost": 2.049,
        "update_date": {
          "$date": "2022-05-30T10:05:23Z"
        }
      },
      {
        "fuel_id": 2,
        "fuel_name": "Gazole",
        "fuel_cost": 1.59,
        "update_date": {
          "$date": "2022-07-14T00:10:19Z"
        }
      },
      {
        "fuel_id": 5,
        "fuel_name": "E10",
        "fuel_cost": 2.009,
        "update_date": {
          "$date": "2022-05-30T10:05:23Z"
        }
      }
    ]
}

So far, I've created the following function:

def update_new_price(station_id, fuel_id, fuel_name, cost):
    query = {'station_id':station_id, 'price_detail.fuel_id':fuel_id, 'price_detail.fuel_name':fuel_name,'price_detail.fuel_cost':cost}
    new_value = {
        '$push':{
            'price_detail':{
                [{'price_detail.fuel_id': fuel_id,'price_detail.fuel_name':fuel_name ,'price_detail.fuel_cost':cost}]
            }}}
    result = db[CL_PRICE].find(query)
    if not list(result):
        db[CL_PRICE].update_one(query,new_value,upsert= True)
        print('new value added')
    else:
        print('Already exists')

Once I run my code, I'm getting an error message.

  'price_detail':{
TypeError: unhashable type: 'list'

Any idea why and how can I fix it?

1 Answers

I think you need to remove extra curved braces there.

Instead of

            'price_detail':{
                [{'price_detail.fuel_id': fuel_id,'price_detail.fuel_name':fuel_name ,'price_detail.fuel_cost':cost}]
            }

it shoild be

            'price_detail': [
                {'price_detail.fuel_id': fuel_id,'price_detail.fuel_name':fuel_name ,'price_detail.fuel_cost':cost}
            ]

You are effectively trying to create a set consisting of a single element which is a list. And set could contain only hashable objects which a list is not.

A minimal reproducible example would be

>>> {[1, 2, 3]}
Traceback (most recent call last):
  Input In [2] in <cell line: 1>
    {[1, 2, 3]}
TypeError: unhashable type: 'list'

The {} without : in between is the syntax for creating a set. Just for clarity, here are some examples of the correct way of creating a set.

>>> {(1, 2, 3)}  # a set containing a single tuple
{(1, 2, 3)}
>>> {*[1, 2, 3]}  # a set of three elements created from a list
{1, 2, 3}
>>> {1, 2, 3}  # a set created from three values
{1, 2, 3}
>>> {x for x in range(1, 4)}  # a set comprehension expression
{1, 2, 3}
Related