I have the following schema for users table:
name: string
emails: [string] // unique index
The index is created in the following way (in go language):
usersCollection.EnsureHashIndex(
ctx,
[]string{"emails[*]"},
driver.EnsureHashIndexOptions{Unique: true, Sparse: true})
Let's say I have the following user in the DB:
{_key: "1", name: "A", emails: ["aa#aa.aa"]}
Adding an email using the following command in arangosh returns an error:
> db.users.update("1", {emails: ["aa#aa.aa", "aa2#aa.aa"]})
JavaScript exception in file '/usr/share/arangodb3/js/client/modules/#arangodb/arangosh.js' at 99,7: ArangoError 1210: unique constraint violated - in index 442818 of type rocksdb-hash over ["emails[*]"]; conflicting key: 1
Using replace returns similar error.
How can I properly add an email to the given user?
I'm demonstrating this in arangosh. Creating the collection:
db._create('usersCollection')
[ArangoCollection 497, "usersCollection" (type document, status loaded)]
Add the unique index to the collection:
db.usersCollection.ensureIndex({ type: "hash", fields: [ "emails[*]" ], unique: true, sparse: true })
{
"deduplicate" : true,
"fields" : [
"emails[*]"
],
"id" : "usersCollection/517",
"isNewlyCreated" : true,
"selectivityEstimate" : 1,
"sparse" : true,
"type" : "hash",
"unique" : true,
"code" : 201
}
Create the entry as you did:
db.usersCollection.save({_key: "1", name: "A", emails: ["aa#aa.aa"]})
{
"_id" : "usersCollection/1",
"_key" : "1",
"_rev" : "_YSk15je---"
}
Now we use AQL to update the emails field to add the other email:
db._query(`UPDATE '1' WITH {emails: ["aa#aa.aa", "bb#bb.bb"]} IN usersCollection`)
[object ArangoQueryCursor, count: 0, cached: false, hasMore: false]
Inspecting the reply:
db.usersCollection.toArray()
[
{
"_key" : "1",
"_id" : "usersCollection/1",
"_rev" : "_YSk2J1K--_",
"name" : "A",
"emails" : [
"aa#aa.aa",
"bb#bb.bb"
]
}
]
Apparently this is a bug in ArangoDB and will be solved later on:
https://github.com/arangodb/arangodb/issues/8359
Related
I have a collection created with below index. Only name is of type string and check should be done in case insensitive manner. Only allows 'A' or 'a'
db.collection('myCollection').createIndex(
{ "name": 1, "type": 1, "ref": 1 }, { unique: true, collation: { locale: 'en', strength: 1 }});
})
}
I have tested and it works but I don't understand the error message:
{
"errorMessage": "E11000 duplicate key error collection: my.myCollection index: name_1_type_1_ref_1 dup key: { : \"O1XO\u0006\u000c)MN11\", : \")MB1O1FG1\", : null }"
}
What does the dup key part mean? Is this the correct way to do this?
What is your mongodb server version? I try mongodb 4.0 its work;
//mongodb version 4.0
db.createCollection("TestIndex");
db.getCollection('TestIndex').createIndex(
{ "name": 1, "type": 1, "ref": 1 }, { unique: true, collation: { locale: 'en', strength: 2 }});
db.getCollection('TestIndex').insert({ "name" : "A",
"type" : "B",
"ref" : "C"});
db.getCollection('TestIndex').insert({ "name" : "A",
"type" : "B",
"ref" : "c"});
//E11000 duplicate key error collection: test_db.TestIndex index: name_1_type_1_ref_1 dup key: { : ")", : "+", : "-" }
db.getCollection('TestIndex').drop();
db.createCollection("TestIndex");
db.getCollection('TestIndex').createIndex(
{ "name": 1, "type": 1, "ref": 1 }, { unique: true, collation: { locale: 'en', strength: 3 }});
db.getCollection('TestIndex').insert({ "name" : "A",
"type" : "B",
"ref" : "C"});
//Inserted 1 record(s) in 11ms
db.getCollection('TestIndex').insert({ "name" : "A",
"type" : "B",
"ref" : "c"});
#AlexBlex pointed in comments that this is bug: https://jira.mongodb.org/browse/SERVER-26050
Latest finding
I found that I will have same error message if my existing collection already has any document that is crashed with the creating index. Please confirm that you do not have invalid document before creating the compound index then.
I experienced the same problem, when I did not give the proper index name in options param. MongoDB does not allow us create with duplicate index key but it will make use the involved fields and corresponding value to create the index name (in this case, it is name_1_type_1_ref_1) .
Hence we need to add the name suffix with '_en' or maybe other suffix to avoid the duplicate error like following.
db.collection('myCollection').createIndex(
{ "name": 1, "type": 1, "ref": 1 },
{ name: "name_1_type_1_ref_1_en",
unique: true,
collation: { locale: 'en', strength: 1 }
}
);
then the compound index can be successfully created.
Clearly there is something I'm not understanding here. I perform a Model.findOne() query, followed by a Model.find() query based on the findOne() result.
The document IDs from the Model.find() query look like they're in a different format than when I query the same documents directly from the Mongo shell. I've Googled for an hour, but no luck. What am I missing??
Model.find() results...
{ _id: ObjectID { _bsontype: 'ObjectID', id: 'W_?àÅÜY¼-íbO' }, // <- Problem
salt: 'ULRtWgj0qgblPRbSPwTe4A==',
displayName: 'test tester',
provider: 'local',
username: 'tester',
created: Tue Jun 14 2016 06:36:48 GMT+0200 (Romance Daylight Time),
roles: [ 'user' ],
profileImageURL: 'modules/users/client/img/profile/default.png',
referrers: { level1: ObjectID { _bsontype: 'ObjectID', id: 'W^_ó 5IE\u0013
N\u0010c' } }, // <- Also problem
password: 'jXpp+RJIegHFKD50sL2aOlOUhE0rvYtSJZIDB244SDIw93yrbuFCTUJK3SZIs3F
w0DdHOUzlQoLQwTGEcF67Kg==',
email: 'test#example.com',
lastName: 'tester',
firstName: 'test',
__v: 0
}
Mongo Shell Results
{
"_id" : ObjectId("575f89e0c5dc59bc2ded62d5"), // <- This is different!
"salt" : "ULRtWgj0qgblPRbSPwTe4A==",
"displayName" : "test tester",
"provider" : "local",
"username" : "tester",
"created" : ISODate("2016-06-14T04:36:48.130Z"),
"roles" : [
"user"
],
"profileImageURL" : "modules/users/client/img/profile/default.png",
"referrers" : {
"level1" : ObjectId("575ebef32035ccc8134e1063") // <- This too!
},
"password" : "jXpp+RJIegHFKD50sL2aOlOUhE0rvYtSJZIDB244SDIw93yrbuFCTUJK3S
ZIs3Fw0DdHOUzlQoLQwTGEcF67Kg==",
"email" : "test#example.com",
"lastName" : "tester",
"firstName" : "test",
"__v" : 0
}
>
Can anyone explain to me what concept I'm missing? Most of my find queries are just fine...this is the first time I've encountered this. Thanks in advance.
OK, this is going to sound really stupid, but in my Mongoose.find() results, instead of getting the id with something like results.id or results._id, I got it to match the strangely formatted id with results._id.id (since the _id itself is an object with an id value).
Seems hacky to me, but it works. So now I have something like:
id = results._id.id || results.id;
Seems super weird, but it works.
I'm trying to use meteor-collection2 to validate my collection.
I have a service, on server side :
Meteor.methods
UserSignUpService: (options) ->
# create user
Accounts.createUser options
That I call on client side :
Meteor.call 'UserSignUpService',
email: 'my.email#domain.com'
password: 'mypassword'
profile:
name: 'me'
And this is my schema :
# user profile
UserProfile = new SimpleSchema
name:
type: String
min: 1
max: 50
optional: false
# user
User = new SimpleSchema
emails:
type: [Object]
optional: false
"emails.$.address":
type: String
regEx: SimpleSchema.RegEx.Email
"emails.$.verified"
type: Boolean
createdAt:
type: Date
profile:
type: UserProfile
optional: false
services:
type: Object
optional: true
blackbox: true
# links to user collection
Meteor.users.attachSchema User
But, when user is created, there are not all fields in my mongo collection :
{ "_id" : "ikvBq95JBLXMCSnhT", "emails" : [ { "address" : "my.email#domain.com" } ] }
Whereas it should be :
{ "_id" : "WNkjGFhNkLpRR2Jex", "createdAt" : ISODate("2015-08-06T09:00:59.887Z"), "services" : { "password" : { "bcrypt" : "$2a$10$QvMLuI.Pv0bzzii3ZZP...fHfUlU9KiYfcsC2VHBf6q1OSPM6cfTW" }, "resume" : { "loginTokens" : [ { "when" : ISODate("2015-08-06T09:01:00.002Z"), "hashedToken" : "9KyqjRVSWm0nfIlS0sqODRmddlJ5GaG3mJ4+RMItOhk=" } ] } }, "emails" : [ { "address" : "my.email#domain.com", "verified" : false } ], "profile" : { "name" : "me" } }
Any idea on this problem ?
Many Thanks !
You're not actually setting the createdAt field value, try:
createdAt:
type: Date
autoValue: function(){
if this.isInsert return new Date()
else if this.isUpsert return { $setOnInsert: new Date };
else if this.isSet this.unset();
}
You can also omit optional: false in your schema since that's the default.
Also, and I suspect this is the bigger problem, not all user keys are returned to the client by default, only profile is normally published. For example you're expecting the services key but that doesn't normally come across. Look at the document in the mongo console and see what's there. You might need to publish a more comprehensive set of keys to the client.
I have data in mongodb like this:
{
"_id" : ObjectId("55a12bf6ea1956ef37fe4247"),
"tempat_lahir" : "Paris",
"tanggal_lahir" : ISODate("1985-07-10T17:00:00.000Z"),
"gender" : true,
"family" : [
{
"nama" : "Robert Deniro",
"tempat_lahir" : "Bandung",
"tanggal_lahir" : ISODate("2015-07-09T17:00:00.000Z"),
"pekerjaan" : "IRT",
"hubungan" : "XXX",
"tanggungan" : false,
"_id" : ObjectId("55a180f398c9925299cb6e90"),
"meta" : {
"created_at" : ISODate("2015-07-11T20:59:25.242Z"),
"created_ip" : "127.0.0.1",
"modified_at" : ISODate("2015-07-12T15:54:39.682Z"),
"modified_ip" : "127.0.0.1"
}
},
{
"nama" : "Josh Groban",
"tempat_lahir" : "Jakarta",
"tanggal_lahir" : ISODate("2015-06-30T17:00:00.000Z"),
"pekerjaan" : "Balita",
"hubungan" : "Lain-Lain",
"tanggungan" : true,
"_id" : ObjectId("55a29293c65b144716ca65b2"),
"meta" : {
"created_at" : ISODate("2015-07-12T16:15:15.675Z"),
"created_ip" : "127.0.0.1"
}
}
]
}
when i try to find data in sub-document, with this code:
person.findOne({ _id: req.params.person, {'family.nama': new RegExp('robert', 'gi') }}, function(err, data){
// render code here
});
It show all data in Family Data,
Can we fetch or display a data only match with criteria/keyword, for example only "Robert Deniro" row
Thank You
In 'regular' MongoDB, you can use the $ operator for that. I'm not sure if it works with Mongoose, but it's worth a try:
person.findOne({
_id : req.params.person,
'family.nama' : new RegExp('robert', 'gi')
}, {
// Only include the subdocument(s) that matched the query.
'family.$' : 1
}, function(err, data){
// render code here
});
If you need any of the properties from the parent document (tempat_lahir, tanggal_lahir or gender; _id will always be included), you need to add them to the projection object explicitly.
One caveat: the $ operator will only return the first matching document from the array. If you need it to return multiple documents, you can't use this method and (AFAIK) have to postprocess the results after they are returned from the database.
It solved with this code:
var options = {
family: {
$elemMatch: { nama: req.query.keyword }
},
};
person.findOne({ _id: req.params.person, 'family.nama': keyword }, options, function(err, data){
//render code here
});
Thanks to #hassansin & #robertklep
all
I'm developing an application that store my multimedia catalog, I've JSON collection like this :
{ "_id" : ObjectId( "5142f55394474e2aac000001" ),
"contentType" : "binary/octet-stream",
"length" : 2732376,
"chunkSize" : 262144,
"uploadDate" : Date( 1363342677601 ),
"metadata" : {
"TIT2" : "Chase The Blues (Cameron McVey Remix)",
"TPE1" : "Terranova",
"TRCK" : "1/13",
"TALB" : "!K7",
"TPOS" : "1/1",
"TDRC" : "2000-06",
"TCON" : [
"Electronica",
"Trip-Hop" ],
"COMM" : [
"Chillout",
"Love",
"German",
"Berlin",
"2000s",
"Female Vocalists",
"Male Vocalists" ],
"TMED" : "CD",
"TMOO" : "Chill",
"TDOR" : "2000-06",
"TSO2" : "Various Artists",
"TPE2" : "Various Artists",
"TCMP" : "1",
"TSOP" : "Terranova",
"TIT1" : "Electronica",
"TPUB" : "Sinedín Music",
"TLAN" : "eng",
"TYER" : [
"2000" ],
},
"md5" : "617401af615ac0c6cb1dee9a3f1b99e6",
"origin" : "Chase The Blues.109eb5ab5105a1caa505a26657f7f9a8.mp3",
"evolution" : null,
"insertDate" : Date( 1336662308000 ),
"tagSource" : "MusicBrainz",
"mediainfo" :
{ "Format" : "MPEG Audio",
"Format version" : "Version 1",
"Format profile" : "Layer 3",
"Duration" : "3mn 47s",
"Bit rate mode" : "Constant",
"Bit rate" : "96.0 Kbps",
"Channel(s)" : "1 channel",
"Sampling rate" : "44.1 KHz",
"Compression mode" : "Lossy",
"Stream size" : "2.60 MiB (100%)",
"Language" : "English"
}
}
so, as you can see, there are "metadata" and "mediainfo" array in the document
in the models.js , in the client side, I've rewrite the model parse function like this
var Audio_Model = Backbone.Model.extend({
idAttribute: "_id",
url: 'AudioModel',
urlRoot: 'AudioModel' ,
parse: function(response) {
// Check if response includes some nested collection data...
if (_.has(response, 'metadata')){
// Check if this model has a property called metadata
if (!_.has(this, 'metadata')) { // It does not...
// So instantiate a collection and pass in raw data
this.metadata = new Audio_Collection_Metadata(response.metadata);
} else {
// It does, so just reset the collection
this.metadata.reset(response.metadata);
}
delete response.metadata;
}
// Check if response includes some nested collection data...
if (_.has(response, 'mediainfo')){
// Check if this model has a property called mediainfo
if (!_.has(this, 'mediainfo')) { // It does not...
// So instantiate a collection and pass in raw data
this.mediainfo = new Audio_Collection_Mediainfo(response.mediainfo);
} else {
// It does, so just reset the collection
this.mediainfo.reset(response.mediainfo);
}
delete response.mediainfo;
}
return response;
}
});
so I've created two separate collection of 'metadata' and 'mediainfo'
the problem that I've is how to render 'metadata' and 'mediainfo' in html template because in 'mediainfo' and 'metadata' collection the key, values are not fixed and in 'metadata' some keys are array of values and the number of item in the array are not fixed
I've created backbone.marionette.itemview and compositeview for these two collections but I don't know how to render
Plase, someone have a solutions ?
Best Regards
finally I've fixed the problem myself with a data normalization, this is the new mongoose schema adopted :
var TagSchema = new mongoose.Schema({
value : {type : String, default: '', required: true}
});
var MetadataSchema = new mongoose.Schema({
name : {type: String, default: '', required : true},
values: [TagSchema]
});
var MediainfoSchema = new mongoose.Schema({
name : {type: String, default: ''},
value: {type: String, default: ''}
});
var StreamSchema = new mongoose.Schema({
_id: mongoose.Schema.ObjectId,
TIT2: {type : String, default: '', required: true},
metadata: [MetadataSchema],
mediainfo:[MediainfoSchema]
});
so that with sequence of CollectionView and CompositeView I can browse the entire model
Hope this can help someone