title: Reactor - how to collect found and not found entities into a map, with id as key?
body: <p>Imagine that I upload a list of user ids into server to find them; I want to know which are the id not found in database, so I will be aware of that my local cache of db data, or my real data is broken. Missing ids are useful as feedback in UI and in logs.</p>
  <p>I want to construct a map with key as input id, and value as found entity user in cache/database. If not found, the value is <code>null</code>.  But, <code>ReactiveCrudRepository</code> will return Mono.empty() if <code>findById(id)</code> returns nothing, and consequent mapping will not include not found entity. In test I get error:</p>
  <pre><code>Expected: is &lt;true&gt;
       but: was &lt;false&gt;
  java.lang.AssertionError: 
  Expected: is &lt;true&gt;
       but: was &lt;false&gt;
  </code></pre>
  <p>I am doing:</p>
  <pre><code>return Flux.fromIterable(ids)
              .concatMap(repository::findById) // &lt;--------------- this step only gets found entities
              .collectMap(Customer::getId); // &lt;------------------ so here I get only existent elements(in test, a map with 2 elements)
  </code></pre>
  <p>The key is to know what id is found and what is not. How can I do this in another way in Reactor 3?</p>
  <p>The test:</p>
  <pre><code>    @Test
      void findAllByIdAndMissing() {
          // given
          Customer customer1 = Customer.builder().id(&quot;id1&quot;).build();
          Customer customer2 = Customer.builder().id(&quot;id2&quot;).build();
          // given mocked
          when(cache.getAllPresent(ArgumentMatchers.any())).thenReturn(Collections.emptyMap());
          when(repository.findById(&quot;id1&quot;)).thenReturn(Mono.just(customer1));
          when(repository.findById(&quot;id2&quot;)).thenReturn(Mono.just(customer2));
          when(repository.findById(&quot;id3&quot;)).thenReturn(Mono.empty());
  
          // when
          Map&lt;String, Customer&gt; actual = service.findAllByIdAndMissing(Set.of(&quot;id3&quot;, &quot;id2&quot;, &quot;id1&quot;)).block();
  
          // then
          assertThat(actual.keySet().contains(&quot;id1&quot;), is(true));
          assertThat(actual.keySet().contains(&quot;id2&quot;), is(true));
          assertThat(actual.keySet().contains(&quot;id3&quot;), is(true));
      }
  </code></pre>
  <p>If I add <code>log()</code>:</p>
  <pre><code>:08:03.072 [Test worker] INFO reactor.Flux.Iterable.1 - | onSubscribe([Synchronous Fuseable] FluxIterable.IterableSubscription)
  13:08:03.078 [Test worker] INFO reactor.Flux.FlatMap.2 - onSubscribe(FluxFlatMap.FlatMapMain)
  13:08:03.080 [Test worker] INFO reactor.Flux.FlatMap.2 - request(unbounded)
  13:08:03.081 [Test worker] INFO reactor.Flux.Iterable.1 - | request(256)
  13:08:03.082 [Test worker] INFO reactor.Flux.Iterable.1 - | onNext(id1)
  13:08:03.084 [Test worker] INFO reactor.Flux.FlatMap.2 - onNext(Customer(super=Auditable(super=Customer@196b1, createdAt=null, createdBy=null, modifiedAt=null, modifiedBy=null), schemaVersion=1, internalVersion=null, id=id1))
  13:08:03.145 [Test worker] INFO reactor.Flux.Iterable.1 - | onNext(id2)
  13:08:03.146 [Test worker] INFO reactor.Flux.FlatMap.2 - onNext(Customer(super=Auditable(super=Customer@196b2, createdAt=null, createdBy=null, modifiedAt=null, modifiedBy=null), schemaVersion=1, internalVersion=null, id=id2))
  13:08:03.147 [Test worker] INFO reactor.Flux.Iterable.1 - | onNext(id3)
  13:08:03.148 [Test worker] INFO reactor.Flux.Iterable.1 - | onComplete()
  13:08:03.149 [Test worker] INFO reactor.Flux.FlatMap.2 - onComplete()
  </code></pre>