0

https://mongoplayground.net/p/dsMlfEdSkXP

I want to query documents that the broadcasterUser upvoted. In the link, the broadcasterUser id is "23435553"

In the result, the document with "_id": ObjectId("5e7d7c35d86d85088863f4df")," should NOT be returned, because the broadcaster's voteType is "downVote".

The document with "_id": ObjectId("5e7d7c47d86d85088863f4e0") SHOULD be returned, because the broadcaster's voteType is "upVote".

Why is my $match condition not working?

  {
    $match: {
      "votes.user.id": "23435553",
      "votes.voteType": "upVote",
    }
  }

EDIT: Found my answer, thanks @prasad. https://mongoplayground.net/p/I_W0_BIIVVO

db.suggestions.aggregate([
  {
    $match: {
      "channelId": "23435553",

    }
  },
  {
    $lookup: {
      from: "votes",
      localField: "_id",
      foreignField: "suggestionId",
      as: "votes"
    }
  },
  {
    $match: {
      "votes": {
        "$elemMatch": {
          "user.id": "23435553",
          "voteType": "upVote",

        }
      },

    }
  },

])

I wasn't trying to do any array filtering. I was trying to filter documents, based on the presence of an object in an array.

The desired logic with the 2nd $match operator was "find suggestion documents where, in the votes array, there exists an object with user.id="23435553" AND voteType="upVote".

Eric Guan
  • 15,474
  • 8
  • 50
  • 61
  • Does this answer your question? [Retrieve only the queried element in an object array in MongoDB collection](https://stackoverflow.com/questions/3985214/retrieve-only-the-queried-element-in-an-object-array-in-mongodb-collection) You need to use `filter` to return needed elements from an array, In general if you use `$match` it would return the whole array(eventually respective doc) if at least an element has met the criteria !! – whoami - fakeFaceTrueSoul Mar 27 '20 at 04:39
  • Hmm, i'm not trying to filter the `votes` array. I'm trying to exclude the document itself because the broadcaster's downvote appears in the `votes` array, if that makes sense. – Eric Guan Mar 27 '20 at 04:44
  • 1
    You have to use the [$elemMatch - Specify Multiple Conditions for Array of Documents](https://docs.mongodb.com/manual/tutorial/query-array-of-documents/#specify-multiple-conditions-for-array-of-documents) when specifying multiple conditions on sub-documents in an array. – prasad_ Mar 27 '20 at 04:49
  • @EricGuan : If I understand it correctly do you wanted to return fewer elements in array based than all depends on few conditions right (Additionally if non matched in votes array - entire doc can also be removed from result)? If yes - then `$filter` should work for you, Did you try it out or do you need a query ? – whoami - fakeFaceTrueSoul Mar 27 '20 at 04:56
  • @whoami sorry no. I want to filter documents, not arrays. But the filtering logic needs to search the array for a specific object that matches multiple conditions. – Eric Guan Mar 27 '20 at 05:01
  • @EricGuan : You can try my answer, Using `$elemMatch` doesn't work with the data that you've (As your docs 'votes' array will meet the `elemMatch` criteria & at the same time will not meet it - as you've "user.id": "23435553" with 'upVote' & 'downVote' in same array/same doc - those docs are which you're not looking for) & `$filter` is not needed as you're not altering array, So just use `$ne` - you can still use `$filter` & `$size` but not needed. :-) *So there in test playground you've 3 docs in which only 2nd is returned* !! – whoami - fakeFaceTrueSoul Mar 27 '20 at 05:19
  • @whoami hmm.. i tested it pretty extensively, it works for me. "as you've "user.id": "23435553" with 'upVote' & 'downVote' in same array/same doc". This shouldn't be possible in my app, and I don't see that in the playgrounds i posted? A user can only appear in the votes array once, with 1 voteType. – Eric Guan Mar 27 '20 at 05:28
  • @EricGuan you’ve the same ‘user.id’ twice with upVote & downVote in your votes array.. that’s where I’ve suggested this ‘$all’ with ‘$ne’ :-) – whoami - fakeFaceTrueSoul Mar 27 '20 at 05:34
  • @whoami, the left column contains collections, not arrays. That is, there are 2 collections in the left column, `suggestions` and `votes`, not a single document with 2 arrays. The last 2 votes, by the same user.id, are for different suggestions (look at the suggestionIds, they're different). When i said "votes array", i'm referring to the computed array generated by the `$lookup` operator. There is no actual `votes` array stored in the database. – Eric Guan Mar 27 '20 at 05:37

1 Answers1

0

To return specific elements from an array, you need to do $filter on your projection. instead of $match, your last pipeline query will be something like this

{
    $project: {
      _id: 1, user: 1,
      votes: {
        $filter: {
          input: "$votes",
          as: "item",
          cond: {
            $and: [
              {
                $eq: [
                  "$$item.user.id",
                  "23435553"
                ]
              },
              {
                $eq: [
                  "$$item.voteType",
                  "upVote"
                ]
              }
            ]
          }
        }
      }
    }
  }

The solution is also done in a playground

https://mongoplayground.net/p/J9O-HzHnQNP

Faysal Ahmed
  • 1,592
  • 13
  • 25