Create multiple documents from an array of values in Mongo DB - mongodb

I'm new to MongoDB and I know this might sound silly to many but is there a way(s) where you can create multiple documents from an array of values. I have written some code for this, but is there any other efficient/shorter way of doing that.
tags.map(async tag => {
const tagDoc = await TagModel.create({ tag, postID })
})
Tag Schema -
const tagSchema = new mongoose.Schema({
postID: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Post",
}],
tag: {
type: String,
required: true,
},
}, { timestamps: true })

Case 1 : Storing Tags in Same Collection
in mysql you have to store tags in different table , but in mongodb you can use same collection to store tags as array of string
in your post schema :
const postSchema = new mongoose.Schema({
...
tags: {
type: [String],
required: true,
}
});
when saving post =>
let post = new Post();
...
post.tags = req.body.tags; // ["Tag1","hello","Testing"];
await post.save();
Case 2 : Storing Tags in Different Collection
if you want to store tags in different collection Tag , then you can use Mongoose InsertMany()
let tags = req.body.tags ; // ["Tag1","hello","Testing"];
tagsArray = tags.map((t)=> { return {postID:post._id , tag:t}});
let tagsSaved = await Tag.insertMany(tagsArray);
console.log('tagsSaved=',tagsSaved);

Related

Is possible to have multiple different types of refs for a single attribute in mongoose (mongodb)

I am using mongodb with mongoose. And i am wondering if it is possible to have multiple references for an object id attribute in a schema.
I have tried the code underneath and it did not work.
const Schema = new Schema({
refrens: {
type: ObjectId,
// this did not work
ref: [
"Post",
"Account"
],
required: true
}
});
I know it is possible to remove the ref attribute (field, key) and then all object ids are valid but i want certain object ids to be valid, the object ids of the Post and Account model.
const Schema = new Schema({
refrens: {
// This will allow all different types of object ids to be the value
type: ObjectId,
required: true
}
});
Look like refPath is what you need. You can do something like this:
const Schema = new Schema({
refrens: {
type: ObjectId,
refPath: 'onModel',
required: true
},
onModel: {
type: String,
required: true,
enum: ['Post', 'Account']
}
});

Mongoose - populate multiple ids

I am new to mongoose and I was strugling whole day trying to understand populate. I managed to do simple examples but now I created two schemas:
First which is UserSchema with some user details:
const UserSchema: mongoose.Schema = new mongoose.Schema ({
name: String,
email: String
});
And second which is MatchSchema witch I want to be populated with user details but I am not sure if something like this will work:
const MatchSchema: mongoose.Schema = new mongoose.Schema ({
player_one: {
id: String,
score: Number,
player_details: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
},
player_two: {
id: String,
score: Number,
player_details: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
},
winner: String
},{timestamps: true});
Probably I used something which wont work and any help will be appriciated.
You need to create a Mongoose model using the UserSchema and name it 'User'. You can then create a Match model using the MatchSchema. Assuming the UserSchema and MatchSchema are in the same file, you can add the following:
const User = mongoose.model('User', UserSchema)
const Match = mongoose.model('Match', MatchSchema)
Then when you want to populate the Match model with User data:
let data = Match.find({})
.populate('player_one.player_details')
.populate('player_two.player_details')

Azure CosmosDB indexes collection named "undefined"

I'm following the instructions in this link https://anthonychu.ca/post/cosmos-db-mongoose-discriminators/ to store multiple document types in a single collection within an Azure Cosmos DB (Mongo API).
I'm using mongoose 5.2.10, nodejs 8.12
I do have models with fields set at "unique: true". E.g.
Here is my Base schema:
const mongoose = require('mongoose')
const baseOptions = {
discriminatorKey: '__type',
collection: 'data'
}
module.exports = mongoose.model('Base', new mongoose.Schema({}, baseOptions))
And here's one of the actual models:
const mongoose = require('mongoose')
const uniqueValidator = require('mongoose-unique-validator')
const Base = require('./_Base')
const roles = require('../lib/auth').roles
const UserSchema = new mongoose.Schema({
displayName: { type : String, default: '' },
email: { type : String, unique : true, required: true },
role: { type : String , default: roles.Users },
tenant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Tenant'
}
})
UserSchema.plugin(uniqueValidator)
module.exports = Base.discriminator('User', UserSchema)
All my data gets stored in a collection with the name 'data' as indicated in my Base model, but somehow another collection gets created in Cosmos DB named "undefine" which seems to be related to the indexes of my data collection:
Question: How to prevent the creation of this "undefined" collection and get any index-related data to be placed in the same collection as my data?
Thanks

Mongoose Virtual Populate 4.5 One-to-Many

I'm using the Mongoose 4.5 virtual populate API and am unable to get the virtual field to populate on the one side of a one-to-many.
const FilmSchema = new Schema({
title: String,
slug: String,
director: String
});
const DirectorSchema = new Schema({
name: String,
slug: String
});
DirectorSchema.virtual('films', {
ref: 'Film',
localField: 'slug',
foreignField: 'director'
});
const Film = mongoose.model('Film', FilmSchema, 'film');
const Director = mongoose.model('Director', DirectorSchema, 'director');
Director.find({}).populate('films').exec()
.then(data => res.send(data))
.catch(err => console.log(err));
The director data is output as expected but without any mention of films and without throwing/logging any errors.
In the query log, it looks like Mongoose is trying to do what I ask:
Mongoose: director.find({}) { fields: undefined }
Mongoose: film.find({ director: { '$in': [ 'spielberg', 'zemeckis', 'nolan' ] } }) { fields: undefined }
I've tried several variations, such as:
setting a ref to Director with type: String on FilmSchema.director
setting a ref to Director with type ObjectId on FilmSchema.director
replacing slug with a custom _id String
...and various combinations of the above.
I'm using the docs example and Valeri's recent article as guides.
Does anyone see what I'm doing wrong?
Versions: Node: 6.3.0 / MongoDB: 3.2.5 / Mongoose: 4.5.8
Answered by vkarpov15 on GitHub issues:
Try res.send(data.toObject({ virtuals: true })); or setting schema.options.toJSON = { virtuals: true }. Virtuals are not included by default when you transform a mongoose doc into a pojo
If you have set schema.options.toJSON = { virtuals: true } and are still not seeing your populated child objects, try explicitly calling .toJSON() - I was simply console.logging my objects and the data was not showing up! DOH!
ie:
const director = await Director.findOne({}).populate('films');
console.log(director);
>> { _id: 5a5f598923294f047ae2f66f, name: 'spielberg', __v: 0};
but:
const director = await Director.findOne({}).populate('films');
console.log(director.toJSON());
>> { _id: 5a5f598923294f047ae2f66f, name: 'spielberg', __v: 0,
films: [{_id: 5a5f598923294f047ae2f6bf, title:"ET"},{_id: 5a5f598923294f047ae2f30v, title:"Jaws"}]
};

Mongoose/MongoDB - Saving a record to overwrite current data:

So I have a object in the DB that is basically blog posts, there is a array of ObjectID's in there that reference the Categories collection.
So
Posts = {
title: String,
Content: String,
Categories: [{
type: ObjectID,
ref: 'Categories'
}]
I can create the posts fine, problem comes when I try to update them:
post.title = 'hi';
post.content = 'content';
post.categories = ['44523452525','4e1342413421342'];
post.save(function(){});
For some reason it will ADD those 2 categories instead of wiping the categories array and inserting those.
How do I get it to remove those and insert new ones?
I tried to reproduce this behavior but I couldn't - here's the code sample I ran:
var mongoose = require('mongoose')
var Schema = mongoose.Schema
mongoose.connect('mongodb://localhost/testjs');
PostSchema = new Schema({
title:String,
content:String,
cats:[]
});
var Post = mongoose.model('Post', PostSchema);
var mypost = new Post()
mypost.title = "x"
mypost.content = "y"
mypost.cats = ['a','b','c']
mypost.save(
function(err){
mypost.cats = ['d','e']
mypost.save()
}
);
After the second call to save() the array contains only what it was set to ("d","e"). Can you try it and see if you get the same result? Maybe it's related to mongoose version, or something.