简体   繁体   中英

MongoDB Track data changes

I want to track changes on MongoDB Documents. The big Challenge is that MongoDB has nested Documents.

Example

[
  {
    "_id": "60f7a86c0e979362a25245eb",
    "email": "walltownsend@delphide.com",
    "friends": [
      {
        "name": "Hancock Nelson"
      },
      {
        "name": "Owen Dotson"
      },
      {
        "name": "Cathy Jarvis"
      }
    ]
  }
]

after the update/change

[
  {
    "_id": "60f7a86c0e979362a25245eb",
    "email": "walltownsend@delphide.com",
    "friends": [
      {
        "name": "Daphne Kline"     //<------
      },
      {
        "name": "Owen Dotson"
      },
      {
        "name": "Cathy Jarvis"
      }
    ]
  }
]

This is a very basic example of a highly expandable real world use chase.

On a SQL Based Database, I would suggest some sort of this solution.

The SQL way

users

_id email
60f7a8b28db7c78b57bbc217 cathyjarvis@delphide.com

friends

_id user_id name
0 60f7a8b28db7c78b57bbc217 Hancock Nelson
1 60f7a8b28db7c78b57bbc217 Suarez Burt
2 60f7a8b28db7c78b57bbc217 Mejia Elliott

after the update/change

users

_id email
60f7a8b28db7c78b57bbc217 cathyjarvis@delphide.com

friends

_id user_id name
0 60f7a8b28db7c78b57bbc217 Daphne Kline
1 60f7a8b28db7c78b57bbc217 Suarez Burt
2 60f7a8b28db7c78b57bbc217 Mejia Elliott

history

_id friends_id field preUpdate postUpdate
0 0 name Hancock Nelson Daphne Kline

If there is an update and the change has to be tracked before the next update, this would work for NoSQL as well. If there is a second Update, we have a second line in the SQL database and it't very clear. On NoSQL, you can make a list/array of the full document and compare changes during the indexes, but there is very much redundant information which hasn't changed.

Have a look at Set Expression Operators

  • $setDifference
  • $setEquals
  • $setIntersection

Be ware, these operators perform set operation on arrays, treating arrays as sets. If an array contains duplicate entries, they ignore the duplicate entries. They ignore the order of the elements.

In your example the update would result in

removed: [ {name: "Hancock Nelson" } ],
added: [ {name: "Daphne Kline" } ]

If the number of elements is always the same before and after the update, then you could use this one:

db.collection.insertOne({
   friends: [
      { "name": "Hancock Nelson" },
      { "name": "Owen Dotson" },
      { "name": "Cathy Jarvis" }
   ],
   updated_friends: [
      { "name": "Daphne Kline" },
      { "name": "Owen Dotson" },
      { "name": "Cathy Jarvis" }
   ]
})


db.collection.aggregate([
   {
      $set: {
         difference: {
            $map: {
               input: { $range: [0, { $size: "$friends" }] },
               as: "i",
               in: {
                  $cond: {
                     if: {
                        $eq: [
                           { $arrayElemAt: ["$friends", "$$i"] },
                           { $arrayElemAt: ["$updated_friends", "$$i"] }
                        ]
                     },
                     then: null,
                     else: {
                        old: { $arrayElemAt: ["$friends", "$$i"] },
                        new: { $arrayElemAt: ["$updated_friends", "$$i"] }
                     }
                  }
               }
            }
         }
      }
   },
   {
      $set: {
         difference: {
            $filter: {
               input: "$difference",
               cond: { $ne: ["$$this", null] }
            }
         }
      }
   }
])

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