简体   繁体   中英

Updating property type and value in a MongoDB document?

I'm building a Node.js application to keep an inventory of books and am using MongoDB and mongoose.

When I first modeled my Schema, there was a genre field of type String which held a single value; in other words, a book could only be assigned one genre.

After adding some "books" into my database, I decided to make a slight change to the Schema design and updated the genre field to genres so that I could instead have an Array of strings . Now every new document I add into the database has a genres field of type Array , but now I'm wondering how to update the documents in the database which reflect the design of the earlier model.

I've started to write a script that:

  1. Iterates through documents in the database where the field genre (singular) exists,
  2. Updates the field name to genres AND sets its value to an array containing whatever value the previous genre property was equal to.

So for instance, (for simplicity's sake I'll use an object with a single property of genre), from this:

{genre: "Philosophy"}

I'm trying to get to this

{genres: ["Philosophy"]}

How can I achieve this? This is the code I have so far

db.books.updateMany({genre: {$exists: true}},{<missing this part>}

You can use aggregation framework to do that:

db.books.aggregate([
    { $match: { genre: { $exists: true } } },
    { 
        $group: {
            _id: "$_id",
            genres: { $push: "$genre" },
            fst: { $first: "$$ROOT" }
        } 
    },
    {
      $replaceRoot: { newRoot: { $mergeObjects: ["$fst",  "$$ROOT" ] } }
    },
    { $project: { fst: 0, genre: 0 } },
    { $out: "books" }
])

$group is a way of transforming property to an array (each group will contain only one element since we're grouping by unique _id ). Using $replaceRoot with $mergeObjects you can merge all your properties from original object with your new array. Then you need to remove unnecessary fields using $project. Last step which is $out will redirect the output of this aggregation into specified collection, causing updates in this case.

You want to iterate over every element in your db:

 db.books.find({genre: {$exists: true}}).forEach(doc => {

Then you want to update that element:

 if(Array.isArray(doc.genre)) return;

 db.books.updateOne(doc, { $set: { genre:[doc.genre]} });

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