How to update an element of an array of strings on Mongoose? - node.js

I'm trying to update an element of an array inside my model. It's a simple array of Strings. When I run the code, the element is updated, but it's inserting a new array with the value 'newType'. I'm using mongoose 4.11.7.
The result I expect is:
['a', 'b', 'newType'] but after the update it's returning ['a', 'b', ['newType']].
const profile = await Profile.findOneAndUpdate({
_id: 1,
types: 'oldType'
}, {
$set: {
'types.$': 'newType'
}
});
My Model is:
const schema = new Schema({
types: [{
type: String,
trim: true
}]
}, {
timestamps: true,
collection: 'Profile'
});

Related

Mongoose find Object where query contains an array of objects based on the ObjectId

I would like to query a model with an array of objects in a async function.
My ContractSchema:
const ContractSchema = new mongoose.Schema({
Nr: {
type: String,
trim: true,
sparse: true,
},
});
My StationSchema
const StationSchema = new mongoose.Schema({
ContractId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Contract',
required: true,
},
Name: {
type: String,
trim: true,
},
});
My first query works, as a result I am getting two objects:
const contract = await Contract.find({ Nr: 'pi' });
My second query, as a result I should get 2 objects. But I am getting a lot of objects where ContractId is NULL.
const station = await Station.find({ ContractId: { $in: contract._id } });
For a test I changed the second query, and I am getting the two results:
const station = await Station.find({ ContractId: { $in: ['...9b', '...b4'] } });
For my second query I would like to get teh two result without any NULL value, how do I? What should this query look like?

How to inset multiple documents in mongoose with mongoose required validation?

I wanted to insert multiple documents in my MongoDB collection. I was able to do that by using Model.collection.insert function but when I insert those data it skip/bypass required validation.
I've tried Model.collection.insert([{data: '1'}, {data: '2'}, {type: '3'}]) but this way it's skip or bypass the validation. I want data field required and I used in my Schema that as required. But that's not working.
There is my schema that required a field.
export const SubjectSchema = new mongoose.Schema({
title: { type: String, required: [true, "title field required"] },
groups_id: { type: String },
class_id: { type: String },
meta: { type: Object }
},
{ timestamps: true })
Here is my function
async createSubject(body) {
let result = SubjectSchema.collection.insert(body)
return result
}
I want multiple data to be stored and in each record, title field should be required
Model.insertMany([{data: '1'}, {data: '2'}, {type: '3'}])
you can find the insertMany ref here
however, you can also db.collection.validate()

Mongoose Populate Returns Some Empty Objects

I have 1 main collection and 1 collection with a ref to the main one. Code looks like :
// Ref schema
const onlineSchema = mongoose.Schema({
_id: {
type: Number,
ref: 'Player',
unique: true
}
}, {
timestamps: true
});
//main schema
const playerSchema = mongoose.Schema({
_id: { // User ID
type: Number,
required: true,
unique: true,
default: 0
},
firstname: {
type: String
},
name: {
type: String,
required: true
},
lastname: {
type: String
},
barfoo: {
type: Boolean
}
...
})
I populate it with this code :
var baz = bar;
...
Online.find().populate({
path: '_id',
match: {
[ baz + 'foo']: true
}
}).exec(function(err, online) {
if (err) {
winston.error(err);
} else {
winston.error(util.inspect(online, {
showHidden: false,
depth: null
}));
}
});
If there are 10 elements in online and only 7 match [ baz + 'foo']: true I get 7 proper arrays and 3 empty arrays that look like this:
{ updatedAt: 2016-12-23T18:00:32.725Z,
createdAt: 2016-12-23T18:00:32.725Z,
_id: null,
__v: 0 },
Why is this happening and how to I filter the final result so it only shows the matching elements?
I can use filter to remove the null arrays after I get the result but I'd like to know how to prevent the the query from passing null arrays in the first place.
Why is this happening ?
This is happening because you get all the documents with Online.find() but the player will be populated only for records that match your condition. Your match is for the populate, not for the find() query.
How do I filter the final result so it only shows the matching
elements ?
You cant find a nested elements of a referenced collections since there is no join in MongoDB. But you can :
keep your schema and use aggregation with $lookup :
Online.aggregate(
[{
$lookup: {
from: "players",
localField: "_id",
foreignField: "_id",
as: "players"
}
}, {
$unwind: "$players"
}, {
$match: {
'players.barfoo': true
}
}],
function(err, result) {
console.log(result);
});
change your schema to include Player as a subdocument :
const playerSchema = new mongoose.Schema({
//...
});
const onlineSchema = new mongoose.Schema({
player: playerSchema
}, {
timestamps: true
});
var Online = mongoose.model('Online', onlineSchema);
Online.find({'player.barfoo':true}).exec(function(err, online) {
console.log(online);
});
Dont make _id the reference of another schema, instead make another field name player and give reference through that.
const onlineSchema = mongoose.Schema({
player: {
type: Number,
ref: 'Player',
unique: true
}
}, {
timestamps: true
});
Population:
Online.find().populate({
path: 'player',
match: {
[ baz + 'foo']: true
}
}).exec(...);
dont use _id to ref field.. because its default filed in mongoDB to create index unique.. change you're field name

associative array does not save mongoose

tournament.js
var mongoose = require('mongoose');
var TournamentPlayer = require('../models/tournamentPlayer');
var SportPlayer = require('../models/sportPlayer');
var Schema = mongoose.Schema;
var TournamentSchema = new Schema({
tournamentPlayers:[{
type: Schema.Types.Mixed,
ref: 'TournamentPlayer'
}],
buyin: Number,
entrants: Number,
prizePool: Number,
name: String,
sport: String,
endOfRegistration:Date,
sportsPlayers:[{
type: Schema.Types.Mixed,
ref: 'SportPlayer'
}],
created: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Tournament', TournamentSchema);
api.js
tournament.tournamentPlayers[player.userId]=player;
console.log("ass array"+util.inspect(tournament.tournamentPlayers,false,null));
console.log("ass array element" + util.inspect(tournament.tournamentPlayers[player.userId] ,false,null));
console.log("ass array just in case"+util.inspect(tournament.tournamentPlayers,false,null));
tournament.tournamentPlayers.push(player);
console.log("push"+util.inspect(tournament.tournamentPlayers,false,null));
Output
ass array[]
ass array element{ username: 'batman',
roster:
{ __v: 0,
userId: '57bb89eb10c4b4ac124980b9',
tournamentId: '57d49f5169cc78ac21c5e791',
_id: '57d4b421315f1b501ad5456f',
playerRoster:
[ { _id: '57cfe922dcba0f295f57e26d', playerFirstName: 'Julio' },
{ _id: '57cfe939dcba0f295f57e274', playerFirstName: 'Odell' } ] },
rank: 'blah',
totalPoints: 0,
userId: '57bb89eb10c4b4ac124980b9',
_id: '57d4b421315f1b501ad54570' }
ass array just in case[]
push[{"username":"batman","roster":{"__v":0,"userId":"57bb89eb10c4b4ac124980b9","tournamentId":"57d49f5169cc78ac21c5e791","_id":"57d4b421315f1b501ad5456f","playerRoster":[{"_id":"57cfe922dcba0f295f57e26d","playerFirstName":"Julio"},{"_id":"57cfe939dcba0f295f57e274","playerFirstName":"Odell"}]},"rank":"blah","totalPoints":0,"userId":"57bb89eb10c4b4ac124980b9","_id":"57d4b421315f1b501ad54570"}]
I am trying to declare and add objects to an associative array. When I look them up, I want to use userId instead of _id. When trying with this code, the object can be called directly tournamentPlayers[userId], but doesn't display as part of the array tournamentPlayers. When I do a regular push, it displays, but this isn't what I want. I am able to use the object, but can't save it through mongoose.
I've seen a couple of questions but they did not answer this. The second answer here has strict: false as a setting, but not for a single schema element.
Mongoose: Saving as associative array of subdocuments vs array of subdocuments
How can I declare and add objects to an associative array in mongoose?

Mongoose Relationship Populate Doesn't Return results

var SecuritySchema = new Mongoose.Schema({
_bids: [{
type: Mongoose.Schema.Types.ObjectId,
ref: 'BuyOrder'
}],
_asks: [{
type: Mongoose.Schema.Types.ObjectId,
ref: 'SellOrder'
}]
});
var OrdersSchema = new Mongoose.Schema({
_security: {
type: Mongoose.Schema.Types.ObjectId,
ref: 'Security'
},
price: {
type: Number,
required: true
},
quantity: {
type: Number,
required: true
}
});
// declare seat covers here too
var models = {
Security: Mongoose.model('Security', SecuritySchema),
BuyOrder: Mongoose.model('BuyOrder', OrdersSchema),
SellOrder: Mongoose.model('SellOrder', OrdersSchema)
};
return models;
And than when I save a new BuyOrder for example:
// I put the 'id' of the security: order.__security = security._id on the client-side
var order = new models.BuyOrder(req.body.order);
order.save(function(err) {
if (err) return console.log(err);
});
And attempt to re-retrieve the associated security:
models.Security.findById(req.params.id).populate({
path: '_bids'
}).exec(function(err, security) {
// the '_bids' array is empty.
});
I think this is some sort of naming issue, but I'm not sure, I've seen examples here and on the moongoose website that use Number as the Id type: http://mongoosejs.com/docs/populate.html
The ref field should use the singular model name
Also, just do:
models.Security.findById(req.params.id).populate('_bids').exec(...
My main suspicion given your snippet at the moment is your req.body.order has _security as a string instead of an array containing a string.
Also, you don't need an id property. Mongodb itself will automatically do the _id as a real BSON ObjectId, and mongoose will add id as a string representation of the same value, so don't worry about that.
While I don't understand your schema (and the circular nature of it?), this code works:
var order = new models.BuyOrder({ price: 100, quantity: 5});
order.save(function(err, orderDoc) {
var security = new models.Security();
security._bids.push(orderDoc);
security.save(function(err, doc) {
models.Security.findById({ _id: doc._id })
.populate("_bids").exec(function(err, security) {
console.log(security);
});
});
});
It:
creates a BuyOrder
saves it
creates a Security
adds to the array of _bids the new orderDoc's _id
saves it
searches for the match and populates
Note that there's not an automatic method for adding the document to the array of _bids, so I've done that manually.
Results:
{ _id: 5224e73af7c90a2017000002,
__v: 0,
_asks: [],
_bids: [ { price: 100,
quantity: 5,
_id: 5224e72ef7c90a2017000001, __v: 0 } ] }

Resources