简体   繁体   中英

Find documents where certain field has exact same elements as object in MongoDB and Node.js

I have an array of ids like so:

[5, 7, 9, 4, 18]

I have a collection with documents that are inserted with the following format:

db.collection('groups').insert(
  [
    {
      members: [
        {member: 5, hasSeen: false, requiresAction: true},
        {member: 7, hasSeen: true, requiresAction: true},
        {member: 4, hasSeen: false, requiresAction: false}
      ]
    },
    {
      members: [
        {member: 5, hasSeen: false, requiresAction: true},
        {member: 4, hasSeen: false, requiresAction: false},
        {member: 7, hasSeen: true, requiresAction: true},
        {member: 9, hasSeen: false, requiresAction: false},
        {member: 18, hasSeen: false, requiresAction: false}
      ]
    },
    {
      members: [
        {member: 7, hasSeen: true, requiresAction: true},
        {member: 9, hasSeen: false, requiresAction: false},
        {member: 4, hasSeen: false, requiresAction: false},
        {member: 18, hasSeen: false, requiresAction: false},
        {member: 1, hasSeen: false, requiresAction: false},
        {member: 5, hasSeen: false, requiresAction: true}
      ]
    }
  ]
);

I would like to find all documents in the collection "groups" that contain only the "member" ids in the above array, and order shouldn't matter. For example, if the search was conducted with the above array, only the second inserted document would be returned from above.

You'll need to employ the use of MongoDB's aggregation pipeline to find the required document(s).

The steps to be employed in the aggregation are listed below:

  1. Denormalize each of the documents by deconstructing the members array.

    This can be achieved by using the $unwind aggregation operator:

    Deconstructs an array field from the input documents to output a document for each element. Each output document is the input document with the value of the array field replaced by the element.

    The $unwind operator will split each document into several, each new document containing a members field that has a single member object:

     {_id: 'first_id', members: {member: 4, hasSeen: false}} {_id: 'first_id', members: {member: 5, hasSeen: fasee}}

    To use the $unwind operator, we'd simply add this to the aggregation pipeline:

     {$unwind: "$members"}
  2. Group the documents by their _id fields, adding the member ids to an array

    This can be achieved by using the $group aggregation operator:

    Groups documents by some specified expression and outputs to the next stage a document for each distinct grouping. The output documents contain an _id field which contains the distinct group by key. The output documents can also contain computed fields that hold the values of some accumulator expression grouped by the $group's _id field.

    The $group operator would allow us to group the denormalized documents by their ids while accumulating the member ids so we'll obtain documents of this form:

     {_id: 'first_id', member_ids: [5, 7, 4] }

    The expression required to group the documents and accumulate the ids is:

     {$group: { _id: "$_id", member_ids: { $push: "$members.member" } }}
  3. Filter the resulting documents according to the defined criteria

    This can be achieved by using the $match aggregation operator:

    Filters the documents to pass only the documents that match the specified condition(s) to the next pipeline stage.

    To obtain documents whose member_ids attribute matches the criteria, the expression is:

     {$match: {'member_ids': { $all: [5, 7, 9, 4, 18] } } }

The final aggregation query would be:

db.collection('groups').aggregate(
  [
    {$unwind: "$members"},
    {$group: {
      _id: "$_id",
      member_ids: { $push: "$members.member" }
    }},
    {$match: {'member_ids': { $all: [5, 7, 9, 4, 18] } } }
  ]
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM