fireproofsocks

fireproofsocks

Mongo: too many cursors are already opened

I’m using the mongodb_driver v1.0.0 on an AWS DocumentDB. I ran into a problem
paginating over a large collection (several million rows):

{:error, %Mongo.Error{code: 2, error_labels: [], fail_command: false, host: nil, message: "Cannot open a new cursor since too many cursors are already opened", not_writable_primary_or_recovering: false, resumable: false, retryable_reads: false, retryable_writes: false}}

I guess I haven’t bumbled into this before because I haven’t had to deal with a collection of this size before. I need to grab fields from every document in a collection and write it to PostGres. Hopefully someone can point out what’s wrong with my pattern here…

My first attempt (the one that blew out the number of cursors) was pretty old-school pagination:

defmodule MongoToPostgres do
  require Logger

  @doc """
  ## Examples

      iex> MongoToPostgres.copy_chunk()
  """
  def copy_chunk(next_query \\ %{}) do
    Mongo.Repo.find(
        MyApp.MongoRepo,
        "urls",
        %{
          sort: [_id: 1],
          limit: 250
        }
        |> Map.merge(next_query)
      )
      |> case do
        %Mongo.Stream{docs: []} -> :done
        %Mongo.Stream{docs: docs} -> Logger.debug("Handling #{length(docs)} Mongo docs")
           do_stuff(docs)

          %{"_id" => last_id} = List.last(docs)

          # Loop
          copy_chunk(%{_id: %{"$gt": last_id}})
      end
  end
end

This treats the docs as a list, not as a stream.

Then I tried doing this treating the returned docs as a stream, but I couldn’t quite make sense of the Mongo documentation with the batch_size… I need to go over every element in the collection.

defmodule MongoToPostgres do
  require Logger

  @doc """
  ## Examples

      iex> MongoToPostgres.copy_chunk()
  """
  def copy_chunk(next_query \\ %{}) do
    Mongo.find(MyApp.MongoRepo, "urls", %{
        sort: [_id: 1]
      }, batch_size: 25000)
    |> case do
      %Mongo.Stream{docs: []} ->
        :done

      %Mongo.Stream{docs: docs} ->
        Logger.debug("Handling #{length(docs)} Mongo docs")

        docs
        |> Stream.chunk_every(250)
        |> Stream.each(fn chunk_o_docs ->
          do_stuff_elsewhere(chunk_o_docs)
        end)
        |> Stream.run()
    end
  end
end

Plan B is to use mongoexport to dump this to a CSV and import it that way, but I am curious how this should be structured. Thanks in advance for any pointers!

First Post!

zookzook

zookzook

The find function returns a stream, you can use something like this:

top
|> Repo.find("urls", query, opts)
|> Stream.chunk_very(250)
|> Stream.map(fn chunk -> ... end)
|> Stream.run()

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New

Other popular topics Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement