How to get last inserted id using the JS api? - mongodb

Using the javascript api for MongoDB, how do you get the ID of the last inserted object? i.e.
obj = {a: 1, b: 2};
db.foo.insert(obj);
How do I get the ID for obj?

The people on #mongodb were helpful. The JS API doesn't currently support this, but you can use your own id. To generate a "normal" id, do _id: new ObjectId(). So the example in my question would be:
id = new ObjectId();
obj = {a: 1, b: 2, _id: id};
db.foo.insert(obj);

If you run
db.collection("venues").insert( {name: "test3", FSid: "test3"}, function( err, ret) {
console.log( ret )
})
it returns
{ result: { ok: 1, n: 1 },
ops: [ { name: 'test3', FSid: 'test3', _id: 57cb0a1162cecfe636df6fc1 } ],
insertedCount: 1,
insertedIds: [ 57cb0a1162cecfe636df6fc1 ] }
So you can get your ids along with all inserted objects through:
ret.ops[0]._id
or straight
ret.insertedIds[0]

Now,the mongo native js api supports this. You can get the last id like this:
collection.insert(line, {w : 1}, function(err, inserted) {
inserted[0]._id
}
insert sets the _id property on the inserted object, but it looks like you have to wait for the object to return. The best documentation I've found for this is (unfortunately) in the source code:
https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/collection.js

If you insert the data like this:
var temptodo = new User({
title: data.todo.text,
email: socket.handshake.email,
created_at: Date.now(),
completed: false,
sid: socket.handshake.sid
});
temptodo.save( function(error, User){
console.log("this is the id for the new todo. "+User._id);
console.log('Todo saved in database with sid: '+socket.handshake.sid);
});
Then you can grab the _id like this: console.log("this is the id for the new todo. "+User._id);

Related

BelongsTo in Sails.js

Hello, I need your help please with 2 questions.
I have 2 Models
One to Many
(One) Customer{ id, names, dni} -> Invoice {id, date, ....customer_id} (Many)
1. How can I get this?
I need to consume the api "GET /api/invoices" and that the json return of this, in turn, returns an array
[{
id: 1,
date: '2022-01-01',
....invoice
customer: {
dni: 1,
names: 'Example'
}
},
{
id: 2,
date: '2022-01-02',
....invoice
customer: {
dni: 2,
names: 'Example 2'
}
},
]
So far what I have found in the sailsjs documentation are only examples with POPULATE, where they only show how to list the User model with its corresponding created ones (hasMany)
//var users = await User.find().populate('pets');
// The users object would look something like the following
// [{
// id: 123,
// firstName: 'Foo',
// lastName: 'Bar',
// pets: [{
// id: 1,
// breed: 'labrador',
// type: 'dog',
// name: 'fido',
// user: 123
// }]
// }]
//---This is not what I need.
Is there a function or configuration that I have not found?
Or would I do something like this?
Invoices.find().exec(async(err, invoices)=>{
if(invoices){
for(i = 0; i< invoices.length; i++){
const customer = await Customer.find({id: invoices[i].customer_id});
invoices[i].customer = customer;
}
});
The point is that this takes much longer than doing a query with join
const invoices = await sails.sendNativeQuery('SELECT * from INVOICE A A inner join CUSTOMER B on A.customer_id=B.id ', []);
But I don't know how to get a JSON with the previous structure if I do it by query
2. What is the best option that can solve my problem?
The populate method works in both directions: oneToMany, manyToMany, and manyToOne:
https://sailsjs.com/documentation/reference/waterline-orm/queries/populate
If any condition is required, you could check the details on the section Populating a collection association:
var usersNamedFinn = await User.find({ name:'Finn' })
.populate('currentSwords', {
where: {
color: 'purple'
},
limit: 3,
sort: 'hipness DESC'
});

Embedding fields in all mongodb documents

I have a collection with documents that follows this structure:
child:
{
id: int
name: string
age: int
dob: date
school: string
class: string
}
I would like to embed certain fields, into something like this:
child:
{
id : int
personalInfo {
name: string
age: int
dob: date
}
educationInfo {
school: string
class: string
}
}
How would one go across in doing this in code? I am new to Mongodb, so I apologize if my syntax is incorrect. All of the fields have one-to-one relationships with the child (i.e. one child has one id, one name, one age, one school etc.), so I'm also wondering if embedding is even necessary.
Please try to use $set to set the new field personalInfo and educationInfo, with #unset to remove old fields age, name etc. Before do it, it would be better to check all those fields exists through $exists, here are sample codes as below,
> var personfields = [ "name", "age", "dob" ];
> var educationFields = [ "school", "class" ];
> var query = {};
> personFields.forEach(function(k){ query[k] = {$exists: 1}});
> educationFields.forEach(function(k){ query[k] = {$exists: 1}});
> db.collection.find(query).forEach(function(doc){
var personalInfo = {};
var educationInfo = {};
for (var k in doc) {
if (personFields.indexOf(k) !== -1){
personalInfo[k] = doc[k];
} else if (educationFields.indexOf(k) !== -1) {
educationInfo[k] = doc[k];
}
}
db.collection.update({_id: doc._id},
{$set: {
personalInfo: personalInfo,
educationInfo: educationInfo},
$unset: {'name': '',
'age': '',
'dob': '',
'school': '',
'class': ''}});
})
It's OK to embed them, that's what document dB's are for. So if you need a migration, you'll basically use mongodb's functions like update ,with $set and $unset.
See more here: https://docs.mongodb.org/manual/reference/method/db.collection.update/

MongoDB Function clarification sync insert with auto increment

In the following link from mongoDB documentation:
https://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/
there is an explanation on how to build a "safe" insert with auto-incremental _id.
My questions are:
Where should i define the function at?
How can i call it later on?
I couldn't quit understand if the function is stored as a JS function is a JS file? or is it stored in the DB? or something else.
Thanks.
Here is the actual function as it is brought in the link above:
function insertDocument(doc, targetCollection) {
while (1) {
var cursor = targetCollection.find( {}, { _id: 1 } ).sort( { _id: -1 } ).limit(1);
var seq = cursor.hasNext() ? cursor.next()._id + 1 : 1;
doc._id = seq;
var results = targetCollection.insert(doc);
if( results.hasWriteError() ) {
if( results.writeError.code == 11000 /* dup key */ )
continue;
else
print( "unexpected error inserting data: " + tojson( results ) );
}
break;
}
}
Implementation approach
Here's an example of how to implement an auto-increment field with mongoose:
var CounterSchema = Schema({
_id: {type: String, required: true},
seq: { type: Number, default: 0 }
});
var counter = mongoose.model('counter', CounterSchema);
var entitySchema = mongoose.Schema({
testvalue: {type: String}
});
entitySchema.pre('save', function(next) {
var doc = this;
counter.findByIdAndUpdate({_id: 'entityId'}, {$inc: { seq: 1} }, function(error, counter) {
if(error)
return next(error);
doc.testvalue = counter.seq;
next();
});
});
Source: https://stackoverflow.com/a/30164636/236660
Please note that {_id: 'entityId'} should be set differently per collection you're using this code with. So if you're generating an ID for entitySchema, you'll have {_id: 'entityId'}. For userSchema you would use {_id: 'userId'}, etc. You need to do this so that every collection has its own auto-incremented sequence.
The code above is thread safe. The findByIdAndUpdate operation is atomic; its consistency and concurrency are handled by MongoDB.
Existing module
Also, there is a mongoose module created specifically for handling auto-incremented IDs. You may actually be better off using it:
https://www.npmjs.com/package/mongoose-auto-increment

How do I use new Meteor.Collection.ObjectID() in my mongo queries with meteor?

I have a Collection that has documents with an array of nested objects.
Here is fixture code to populate the database:
if (Parents.find().count() == 0) {
var parentId = Parents.insert({
name: "Parent One"
});
Children.insert({
parent: parentId,
fields: [
{
_id: new Meteor.Collection.ObjectID(),
position: 3,
name: "three"
},
{
_id: new Meteor.Collection.ObjectID(),
position: 1,
name: "one"
},
{
_id: new Meteor.Collection.ObjectID(),
position: 2,
name: "two"
},
]
});
}
You might be asking yourself, why do I even need an ObjectID when I can just update based off of the names. This is a simplified example to a much more complex schema that I'm currently working on and the the nested object are going to be created dynamically, the ObjectID's are definitely going to be necessary to make this work.
Basically, I need a way to save those nested objects with a unique ID and be able to update the fields by their _id.
Here is my Method, and the call I'm making from the browser console:
Meteor.methods({
upChild: function( options ) {
console.log(new Meteor.Collection.ObjectID());
Children.update({_id: options._id, "fields._id": options.fieldId }, {$set: {"fields.$.position": options.position}}, function(error){
if(error) {
console.log(error);
} else {
console.log("success");
}
});
}
});
My call from the console:
Meteor.call('upChild', {
_id: "5NuiSNQdNcZwau92M",
fieldId: "9b93aa1ef3868d762b84d2f2",
position: 1
});
And here is a screenshot of the html where I'm rendering all of the data for the Parents and Children collections:
Just an observation, as I was looking how generate unique IDs client side for a similar reason. I found calling new Meteor.Collection.ObjectID() was returning a object in the form 'ObjectID("abc...")'. By assigning Meteor.Collection.ObjectID()._str to _id, I got string as 'abc...' instead, which is what I wanted.
I hope this helps, and I'd be curious to know if anyone has a better way of handling this?
Jason
Avoid using the _str because it can change in the future. Use this:
new Meteor.Collection.ObjectID().toHexString() or
new Meteor.Collection.ObjectID().valueOf()
You can also use the official random package:
Random.id()

cryptic mongodb error LEFT_SUBFIELD only supports Object: stats not: 6

I'm having trouble figuring out what this error means
LEFT_SUBFIELD only supports Object: stats not: 6
It seems to be happening when I am inserting into my profiles collection. I am using mongoose.js. We are inserting counts of posts in each category in the stats property, e.g.
stats: {category:count, category2: count2}.
Here is my schema
var ProfileSchema = new Schema({
uname: {
type: String,
required: true,
index: true,
unique: true
},
fname: String,
lname: String,
stats: {
type:{},
"default":{},
required:true
},
created: {
type:Date,
required:true,
"default":Date.now
}
});
I think it might be happening when I am updating the stats object $inc counts so that stats can come out to something like this update
db.status.update({_id:xyz}, {$inc: { stats.foo : 1, stats.bar:1}})
Here's my mongoose code
var tags = ["comedy", "action", "drama"];
//also adding the postId to the posts collection of profile
var updateCommand = {$push: {posts: post._id}};
var stats = {};
for (var i = tags.length - 1; i >= 0; i--){
stats["stats." + tags[i].toString()] = 1;
};
updateCommand.$inc = stats;
Profile.update(
{uname: uname},
updateCommand,
{safe:true, upsert:true},
callback
);
It also happens if you're trying to update a subdocument of a non-object.
> db.test.insert({_id: 10240292, object: 'some string'})
> db.test.update({_id: 10240292}, {$set: {'object.subkey': 'some string'}})
LEFT_SUBFIELD only supports Object: object not: 2
Maybe it's not your case, but it can help somebody who googles for this error.
You may be running into this:
https://jira.mongodb.org/browse/SERVER-2651
or
https://jira.mongodb.org/browse/SERVER-5227
Both of which are fixed in the 2.1 dev branch already but not (yet) backported to 2.0
There is a decent discussion here about a similar issue:
https://groups.google.com/forum/?fromgroups#!topic/mongodb-user/VhjhcyEdbNQ
Basically it boils down to the fact that you are likely passing an empty key as part of the update which needs to be avoided.
db.collection('fs.files').update({_id: Object_id}, {$set: {'metadata': {"foo" : "bar"}}}