Reputation: 2867
My question is similar to this question asked in 2016 which unfortunately does not have an accepted answer. I'm also unable to use the answer there to figure out how I need to accomplish the same.
I am basically trying to add a new item to an array in my data model.
My current data model (What I want) is like this:
{
teamId: 'team32',
teamName: 'Lions',
players: ['Jack','Ryan','Sam']
}
When a new team is created, an empty array is added for 'players'. There is no model for players. It is just an array which can hold a list of players.
How do I add a new player to the list of players (Add a string to the list)? I'm also open to storing it as an object instead of string.
My Team model
{
"name": "teams",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"teamID": {
"type": "string",
"required": true
},
"teamName": {
"type": "string",
"required": true
},
"players":{
"type":"array",
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
team.js
var updateQuery = {players:{$addToSet:{'Mark'}}};
team.update({teamID:'teams32'},updateQuery,
function(err,data){
console.log(err,data,'result');
});
$addToSet and $push have both worked for me with MongoDB with mongoose. But somehow don't seem to work on loopback. How do I go about this since $addToSet and $push are both not working for me in this case?
Upvotes: 1
Views: 1563
Reputation: 1651
I have just implemented this endpoint with node --version v10.16.0 and [email protected]
With it I can append values to any field in my model (only handling array type field currently). the data param should look like [ "one", 2, true ]
Dataset.appendToArrayField = function (id, fieldName, data, ctx, next) {
const where = {pid: id};
var $addToSet = {};
// $each is necessary as data is an array of values
// $addToSetis necessary to append to the field and not overwrite
$addToSet[fieldName] = { $each: data };
Dataset.update(where, { $addToSet });
next();
};
Dataset.remoteMethod("appendToArrayField", {
accepts: [{
arg: "id",
type: "string",
required: true,
description: ""
},
{
arg: "fieldName",
type: "string",
required: true,
description: "Name of field to append data to"
},
{
arg: "data",
type: "array",
required: true,
description: "An array of values to append"
},
{
arg: 'options',
type: 'object',
http: {
source: 'context'
}
}
],
http: {
path: "/appendToArrayField",
verb: "post"
},
returns: {
type: "Object",
root: true
},
description: "updates a single record by appending data to the specified field"
});
Upvotes: 0
Reputation: 31
You should extend your model capabilities to use those operators. Something like:
"options": {
"mongodb": {
"collection": "model_collection",
"allowExtendedOperators": true
}
},
As stated in loopback documentation: https://loopback.io/doc/en/lb2/MongoDB-connector.html
Then you can just use it like:
team.update({teamID:'teams32'},{ $addToSet:{ players: 'Mark'}},
function(err,data){
console.log(err,data,'result');
});
Upvotes: 3
Reputation: 171
As of my knowledge the find, update and any other functions here in loopback is not same as MongoDB native query. It has their own customizations. So team.update is not same as db.team.update(). So, Either you can use 2 db queries as said in the previous answer or you can try by running native query by getting the datasource. Then you can use $addToSet easily and it will do the job in a single hit.
team.getDataSource().connector.connect(function (err, db) {
var collection = db.collection("team");
collection.update(filter,{$addToSet: {players:{$addToSet:{'Mark'}}}}, function(err,res){ /*Anything you want to do here*/ })
})
This may help.
Upvotes: 0
Reputation: 2675
This deserves two calls but might help you:
team.addPlayer = function (player, cb) {
team.findOne({where: {teamID: "teams32"}}, function (err, team) {
if (!err && team) {
var players = [];
if (team.players) {
players = team.players;
}
players.push(player);
team.updateAttributes({players: players}, function(err, team) {
cb (err, team);
});
} else {
cb (err, {});
}
});
};
team.remoteMethod('addPlayer', {
accepts: {arg: 'player', type: 'string', required: true},
returns: {arg: 'team', type: 'object'},
http: {verb: 'put'}
});
Upvotes: 1