I have just installed keystone.js and build basic site.
However I noticed that URL contains the mongoDB ID of length 24. that looks ugly.
Any Idea, how can I change it.
http://localhost:3000/keystone/users/56ed6816491debf405f99be1
http://localhost:3000/keystone/posts/56ed086c4b4ba4f8044bbbe1
I want it to be like
http://localhost:3000/keystone/users/enraiser
http://localhost:3000/keystone/posts/my-first-post
We can use auto key of keystones
var Post = new keystone.List('Post', {
autokey: { path: 'slug', from: 'title', unique: true },map: { name: 'title' },
defaultSort: '-createdAt'
});
Create auto-incrementing id field:
https://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/
Related
I'm trying to query an object that's inside an item which is inside a mongoose model, when I'm trying to find that object with the find() method or _.find() method, I can't get access to the object for some reason and when I console.log() it, it gives me undefined or when I use array.filter() it gives me an empty array, which means the object that I'm trying to access does not meet the criteria that I give it in the lodash find method, but then when I look at my database I see that the object does actually have the properties to meet the criteria. So I don't know what I'm doing wrong, here's my code: as you can see I'm trying to get the information of the item that the user clicked on and want to see:
router.get("/:category/:itemId", (req, res) => {
console.log(req.params.itemId);
//gives the item id that the user clicked on
console.log(req.params.category);
//gives the name of category so I can find items inside it
Category.findOne({ name: req.params.category }, (err, category) => {
const items = category.items; //the array of items
console.log(items); //gives an array back
const item = _.find(items, { _id: req.params.itemId });
console.log(item); //gives the value of 'undefined' for whatever reason
});
});
The category Schema:
const catSchema = new mongoose.Schema({
name: {
type: String,
default: "Unlisted",
},
items: [
{
name: String,
price: Number,
description: String,
img: String,
dateAdded: Date,
lastUpdated: Date,
},
],
dateCreated: Date,
lastUpdate: Date,
});
well the answer is a little bit obvious, you are using MongoDB and in Mongo you have "_ID" you can use that "_ID" only with Mongoose! so you just have to remove the underscore and that is it! do it like this const item = _.find(items, { id: req.params.itemId });
hope you are doing better.
When I look at your Schema I see that the item field is an array of objects which doesn't have an _id inside so when you create a new instance of catShema it just generates an _id field for the new instance but not for each item inside the items array, just also enter the id of the item in question because according to my understanding, you must also have a model called items in your database
When you save these records in your database, you will generate an element with this structure
{
_id: String, // auto generated
name: String,
items: [ {"name1", "price1", "description1", "imgUrl1", "dateAdded1", "lastUpdated1"},{"name2", "price2", "description2", "imgUrl2", "dateAdded1", "lastUpdated2"}, ...],
dateCreated: Date,
lastUpdate: Date
}
Note : the code provided at the top is only an illustration of the object which will be registered in the database and not a valid code
Here you can notice that there is not a field called _id in the object sent inside the database.
My suggestion to solve this issue is
To create an additional field inside the items array called _id like :
{
...,
items: [
{
_id: {
type: String,
unique : true,
required: true // to make sure you will always have it when you create a new instance
},
...
... // the rest of fields of items
},
...
Now when you create a new instance make sure in the object you enter in the database the _id is recorded when you call the catInstance.save() so inside the catInstance object you have to add the current Id of the element to be able to filter using this field.
Hope my answer helped, if you have any additional questions, please let me know
Happy coding ...
I have a dynamo db schema lets say goes like this
const team = new dynamoose.Schema(
{
bitbucketDetails: [
{
id: {
type: String,
required: true,
},
repository: {
type: String,
},
},
],
})
I wanted to search for an item having lets say particular repository "abc". how can i search that?
so far i tried something like
team.scan({ bitbucketDetails: { contains:"abc" }}).all().exec()
but keep saying ValidationException: One or more parameter values were invalid: ComparisonOperator CONTAINS is not valid for M AttributeValue type.
Please help!!
You are looking for the value in bitbucketDetails, but you want to look in bitbucketDetails.repository.
First of all, I'm coming from years of using Django and relational databases, but want to try something new - so this is probably a conceptual problem on my part. I'm just not sure where it is. Hope the question is clear enough, even though I'm not sure what I should be asking...
So. I'm setting up an application that contains Teams, and Matches between these teams.
Here are my models:
var TeamSchema = new Schema({
name: String,
code: String
});
TeamSchema.statics = {
list: function(options, cb) {
var criteria = options.criteria || {};
this.find(criteria)
.exec(cb);
},
load: function(id, cb) {
this.findOne({_id: id})
.exec(cb);
},
};
var MatchSchema = new Schema({
home_team: { type: Schema.ObjectId, ref: 'Team' },
away_team: { type: Schema.ObjectId, ref: 'Team' },
datetime: Date,
slug: String,
home_score: Number,
away_score: Number
});
Where I run into problems is when I want to populate these models programmatically. The teams are easy enough:
// Clear old teams, then add default teams
Team.find({}).remove(function() {
Team.create({
name: 'Brazil',
code: 'bra'
}, {
name: 'Cameroon',
code: 'cmr'
}, {
name: 'Spain',
code: 'esp'
}, {
....
But then I want to create matches, which requires getting the _ids for the teams. In my way of thinking this is pretty easy: Create the Teams, then before creating the Matches fetch the appropriate Teams and assign to variables, and finally create a Match using these variables to populate the home_team and away_team fields.
This of course doesn't work here, since there's no guarantee the Teams have been populated when the Match creating function is called. So I moved that code to the callback of the Team creation code. But still that didn't work, since when the Match is created the Team variables are still not populated. I sort of got this to work by putting the match creation code as a callback to the Team lookup (which itself is a callback to the Team creation code). But that only works for ONE of the Teams, how do I ensure I have both the _ids available before creating a Match?
As I said in the beginning, I feel like I'm thinking about this the wrong way - so I'm not necessarily looking for working code, more for pointers about where I'm going wrong in my thinking.
That said, this is the working code I have for setting one of the teams:
// Clear old teams, then add default teams
Team.find({}).remove(function() {
Team.create({
name: 'Brazil',
code: 'bra'
}, {
name: 'Croatia',
code: 'hrv'
},
function() {
console.log('finished populating teams');
// Clear old matches, then add default matches
Match.find({}).remove(function() {
Team.findOne({code: 'bra'}, function(err, obj) {
if (!err) {
console.log(obj.code);
Match.create({
datetime: "2014-06-01T22:00:00.000Z",
slug: 'bra-hrv',
home_team: obj._id
});
} else {
console.log(err);
}
});
});
});
});
Edit: Found one way around it. Since code is unique to each team, I switched the team _id field to String and removed code. That way I can easily create the Match objects without having to look up the _id - I already know what it is.
Doesn't really solve my underlying problem, but it does get the work done.
If you use new and save to create your Team docs you'll have immediate access to their _id values because they're assigned client-side:
var brazil = new Team({
name: 'Brazil',
code: 'bra'
});
brazil.save();
var croatia = new Team({
name: 'Croatia',
code: 'hrv'
});
croatia.save();
Match.create({
datetime: "2014-06-01T22:00:00.000Z",
slug: 'bra-hrv',
home_team: brazil._id,
away_team: croatia._id
});
I'm using Sails.js (0.9.8) and MongoDB (via the sails-mongo adaptor) to create a collection of pages that can be positioned in a tree-view. I would like to store the path of a page in an array of UUIDs
My model:
module.exports = {
schema: true,
attributes: {
uuid: {
type: 'string',
unique: true,
required: true,
uuidv4: true
},
name: {
type: 'string',
required: true,
empty: false
},
path: {
type: 'array',
required: true,
array: true
}
}
}
It works well when I save a 'root' page (the 'path' property has just one item because it's a root page. Here is what it was saved in MongoDB:
{
_id: ObjectId("52f853e9609fb6c0341bdfcc"),
createdAt: ISODate("2014-02-10T04:22:01.828Z"),
name: "Home Page",
path: [
"a2b23e1f-954b-49a3-91f1-4d62d209a093"
],
updatedAt: ISODate("2014-02-10T04:22:01.833Z"),
uuid: "a2b23e1f-954b-49a3-91f1-4d62d209a093"
}
But when I want to create a 'subpage' below my previous created page (Home Page/Products), I get this error:
MongoError: E11000 duplicate key error index: cms-project.item.$path_1
dup key: { : "a2b23e1f-954b-49a3-91f1-4d62d209a093" }
Here is the data I sent:
{ name: 'Products',
uuid: 'a004ee54-7e42-49bf-976c-9bb93c118038',
path:
[ 'a2b23e1f-954b-49a3-91f1-4d62d209a093',
'a004ee54-7e42-49bf-976c-9bb93c118038' ] }
I probably missed something but I don't know what.
If I store the path in a string instead of an array, it work well, but I find it much less elegant and handy.
Not sure of all the Sails / Waterline parts myself as I've never played with it. But by the error the problem is there is a unique index on your array field.
When you are inserting your second document, you already have one of the values (the parent) in your path field in another document. The unique constraint is not going to allow this. Most certainly for what you are modelling, you do not want this and the index cannot be unique.
I hope that you set this up yourself under the assumption that it meant unique within the array contained in the document. If you did then you know where to look and what to change now. If this is being automatically deployed somehow, then I'm not the one to help.
Change the index to not be unique. You can confirm this through the mongo shell:
use cms-project
db.item.getIndices()
Good luck
We're rapidly developing an application that's using Mongoose, and our schema's are changing often. I can't seem to figure out the proper way to update a schema for existing documents, without blowing them away and completely re-recreating them from scratch.
I came across http://mongoosejs.com/docs/api.html#schema_Schema-add, which looks to be right. There's little to no documentation on how to actually implement this, making it very hard for someone who is new to MongoDB.
I simply want to add a new field called enabled. My schema definition is:
var sweepstakesSchema = new Schema({
client_id: {
type: Schema.Types.ObjectId,
ref: 'Client',
index: true
},
name: {
type: String,
default: 'Sweepstakes',
},
design: {
images: {
type: [],
default: []
},
elements: {
type: [],
default: []
}
},
enabled: {
type: Boolean,
default: false
},
schedule: {
start: {
type: Date,
default: Date.now
},
end: {
type: Date,
default: Date.now
}
},
submissions: {
type: Number,
default: 0
}
});
Considering your Mongoose model name as sweepstakesModel,
this code would add enabled field with boolean value false to all the pre-existing documents in your collection:
db.sweepstakesModel.find( { enabled : { $exists : false } } ).forEach(
function (doc) {
doc.enabled = false;
db.sweepstakesModel.save(doc);
}
)
There's nothing built into Mongoose regarding migrating existing documents to comply with a schema change. You need to do that in your own code, as needed. In a case like the new enabled field, it's probably cleanest to write your code so that it treats a missing enabled field as if it was set to false so you don't have to touch the existing docs.
As far as the schema change itself, you just update your Schema definition as you've shown, but changes like new fields with default values will only affect new documents going forward.
I was also searching for something like migrations, but didn't find it. As an alternative you could use defaults. If a key has a default and the key doesn't exist, it will use the default.
Mongoose Defaults
Default values are applied when the document skeleton is constructed. This means that if you create a new document (new MyModel) or if you find an existing document (MyModel.findById), both will have defaults provided that a certain key is missing.
I had the exact same issue, and found that using findOneAndUpdate() rather than calling save allowed us to update the schema file, without having to delete all the old documents first.
I can post a code snippet if requested.
You might use mongo shell to update the existing documents in a specific collection
db.SweeptakesModel.update({}, {$set: {"enabled": false}}, {upsert:false, multi:true})
I had a similar requirement of having to add to an existing schema when building an app with Node, and only found this (long ago posted) query to help.
The schema I added to by introducing the line in the original description of the schema and then running something similar to the following line, just the once, to update existing records:
myModelObject.updateMany( { enabled : { $exists : false } }, { enabled : false } )
'updateMany' being the function I wanted to mention here.
just addition to what Vickar was suggesting, here Mongoose Example written on Javascript (Nodejs):
const mongoose = require('mongoose');
const SweeptakesModel = mongoose.model(Constants.SWEEPTAKES,sweepstakesSchema);
SweeptakesModel.find( { enabled : { $exists : false } }).then(
function(doc){
doc.enabled = false;
doc.save();
}
)