Setting custom _id value on upsert?

841 views
Skip to first unread message

mguserdev

unread,
Oct 29, 2011, 9:32:19 AM10/29/11
to mongodb-user
Is it possible to set a custom value for the _id field on an upsert?

I tried the following but it gave me an error:

> db.things.update( {name:'bbb'}, {$set:{_id:234}, $inc:{x:2, y:2}}, true);
Mod on _id not allowed

Scott Hernandez

unread,
Oct 29, 2011, 10:11:49 AM10/29/11
to mongod...@googlegroups.com
Put it in the query part.

> --
> You received this message because you are subscribed to the Google Groups "mongodb-user" group.
> To post to this group, send email to mongod...@googlegroups.com.
> To unsubscribe from this group, send email to mongodb-user...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/mongodb-user?hl=en.
>
>

mguserdev

unread,
Oct 29, 2011, 10:47:01 AM10/29/11
to mongodb-user
I tried putting the new value for _id inside the query and it did not
work (created a new doc with _id = newId instead of updating the old
doc with _id = 4eabff2e493e3cf75aa54b74). Did I write the query
incorrectly? To clarify, I need to perform an upsert in which if an
insert occurs as opposed to an update, the _id value of the insert is
defined as 'newId', instead of the default ObjectId() used by mongodb.

> db.things.find();
{ "_id" : ObjectId("4eabff2e493e3cf75aa54b74"), "_name" : "bbb", "x" :
6, "y" : 6 }

> db.things.update( {_name:'bbb', _id:'newId'}, {$inc:{x:2, y:2}}, true);

> db.things.find();
{ "_id" : ObjectId("4eabff2e493e3cf75aa54b74"), "_name" : "bbb", "x" :
6, "y" : 6 }
{ "_id" : "newId", "_name" : "bbb", "x" : 2, "y" : 2 }

Andreas Jung

unread,
Oct 29, 2011, 11:16:52 AM10/29/11
to mongod...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

You can not change the _id of a document. It's immutable.

- -aj

- --
ZOPYX Limited | zopyx group
Charlottenstr. 37/1 | The full-service network for Zope & Plone
D-72070 T�bingen | Produce & Publish
www.zopyx.com | www.produce-and-publish.com
- ------------------------------------------------------------------------
E-Publishing, Python, Zope & Plone development, Consulting


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQGUBAEBAgAGBQJOrBjkAAoJEADcfz7u4AZj1/wLvi5OcQ3EXqp0udFwX/RS82Fx
aA5SGdY8pJnvMAYrPu57SUChSA+qnYEYANKLk3NB9rilcMCWTt7pyaSb9n/NWsx3
3idDytuMJPLnaUvk5ahSHWyGpyvIaKDCyhrsn4dM+IVCtcl7yMEgVBrPjqSCMQrz
08+xgyp/hCW2LOQiI9oNWzGncu0gn6I6D48oLs6jVLb9Da8o1AAR6rCAkl5KZwU9
wIaw23HQsuQriCbk7cJHjtt0n/M+dRPFjhLlWd7zn3dbFcDiMHQN04pYQGL3Fy+h
QUovy/dQaXWE3AiSwibmPHTjEEuyHhHy9//hipRrjYmhB3bVVSIHwTDRa73rZS8x
VA2RDKavRGjzSL75F83L1COMczn2eCwmOvK6UUAtoQTClgKG6hmA1H29V2Jtq29l
nYZY3zfBCqoaLjSkYE0cKShKI1MpshWXpsw7U3kLh5Oz6tE8lQ/qb6h5NBnBVS91
8fNBWchzGPBZfgHrLtN5Onr8oOpmWqQ=
=j42v
-----END PGP SIGNATURE-----

lists.vcf

Scott Hernandez

unread,
Oct 29, 2011, 11:26:55 AM10/29/11
to mongod...@googlegroups.com
It depends what you "mean" to do.

Update w/upsert = update the doc if found, else insert a new document
(take the query, apply the updates and insert).

Are you just trying to find the document with the name:"xxx", and you
don't know the _id? It seems like your aim is at odds logically with
what you are trying to do.

If you are basically trying to change the _id field, which is
basically what your update statement looks like, then you should just
go through all the existing ones and do that (remove + insert
w/new-_id).

Here are some more docs which may help you to understand things a bit
better. http://www.mongodb.org/display/DOCS/Updating

mguserdev

unread,
Oct 29, 2011, 12:10:19 PM10/29/11
to mongodb-user
To provide more detail, here is my situation. I have a collection in
mongodb that has about 100,000 documents imported from a mysql table,
and all the docs have an _id value that is an integer (the mysql table
had an auto-increment field). This collection's purpose is to track
various counters, so I need the upsert capability. In mysql, I would
do UPDATE ... ON DUPLICATE KEY...

The problem I am running into is that when I do the mongodb upsert, if
none of the existing 100,000 docs match the upsert criteria, a new doc
is inserted. The new doc being inserted is OK since that is exactly
what is desired, and is consistent with mysql's UPDATE ... ON
DUPLICATE KEY... However, mongodb is inserting the new doc with _id
being set to something like 4eabff2e493e3cf75aa54b74, which is
inconsistent with the _id value being simple integers for the 100,000
other docs in the collection, and would also make it impossible for me
to move the data from the mongodb collection back to mysql at a future
date (as the 4eabff2e493e3cf75aa54b74 cannot be inserted into an
integer column in mysql).

So, I need a way to do an upsert in mongodb in which if a NEW doc is
inserted, the _id value of that new doc is a custom _id value that I
get to define in the upsert command, not the auto-generated
4eabff2e493e3cf75aa54b74 value that mongodb is using by default.

On Oct 29, 11:26 am, Scott Hernandez <scotthernan...@gmail.com> wrote:
> It depends what you "mean" to do.
>
> Update w/upsert = update the doc if found, else insert a new document
> (take the query, apply the updates and insert).
>
> Are you just trying to find the document with the name:"xxx", and you
> don't know the _id? It seems like your aim is at odds logically with
> what you are trying to do.
>
> If you are basically trying to change the _id field, which is
> basically what your update statement looks like, then you should just
> go through all the existing ones and do that (remove + insert
> w/new-_id).
>
> Here are some more docs which may help you to understand things a bit
> better.http://www.mongodb.org/display/DOCS/Updating

Andreas Jung

unread,
Oct 29, 2011, 12:55:20 PM10/29/11
to mongod...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

mguserdev wrote:

>
> So, I need a way to do an upsert in mongodb in which if a NEW doc is
> inserted, the _id value of that new doc is a custom _id value that I
> get to define in the upsert command, not the auto-generated
> 4eabff2e493e3cf75aa54b74 value that mongodb is using by default.
>

What is the problem? Why don't you specify your custom _id
as part of the query clause *and* the update clauses?

- -aj

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQGUBAEBAgAGBQJOrC/4AAoJEADcfz7u4AZjs6oLvi3+vE47pMiKYgxhe06ys8/6
g+QaqmQLSzMB+Vs200YCCce5tbMJmCw93f6dBOw6QYzHvzTegF1n3UO9ThFdMgmY
0ncZTdgedhZcPix7D8rgTLRO4out/8vXECSgHRxm+ZW5w+dm86fF6CnXXwaBjB+n
jU2kHA3SA4kmTfY9MhosRF9R+yXlyfmEBc3qfQ7nmSjgtQ6/X4elk+fmi9sXRb73
JwGYWGJ3r2Van4iRCI0PRfsDJj6B2MSI3ZbS1NSTpLzLmTkExvRiRtxQKo8oDPs3
e6nP1hgcZptvd/LKwNnl3JPPWvqpVhbY8TUPhlTW5oVuTiX4uzPdMYK5uNJMG31T
sj8wdb13HvP7ynmjpDKnG7oxN3j6y+6h/5U5BEP4Ok6XX+Ik14fRSMMBLQUstHDT
6THN5rE/QQZ2ofYleUAM/jBQqTGT1USa7cQ7gCPHv6olNsgXdHiVydhhsDXXTkTL
8VdvsJjsP5KYEbc7rTMJqxrdvd/wSrs=
=78F1
-----END PGP SIGNATURE-----

lists.vcf

mguserdev

unread,
Oct 29, 2011, 1:08:01 PM10/29/11
to mongodb-user
Can you provide a sample command that does this?

I tried both of the following commands and got an error "Mod on _id
not allowed"

> db.things.update( {name:'ccc'}, {$set:{_id:345}, $inc:{x:2, y:2}}, true);
Mod on _id not allowed

> db.things.update( {_name:'ccc',_id:345}, {$set:{_id:345}, $inc:{x:2, y:2}}, true);
Mod on _id not allowed


On Oct 29, 12:55 pm, Andreas Jung <li...@zopyx.com> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> mguserdev wrote:
>
> > So, I need a way to do an upsert in mongodb in which if a NEW doc is
> > inserted, the _id value of that new doc is a custom _id value that I
> > get to define in the upsert command, not the auto-generated
> > 4eabff2e493e3cf75aa54b74 value that mongodb is using by default.
>
> What is the problem? Why don't you specify your custom _id
> as part of the query clause *and* the update clauses?
>
> - -aj
>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.11 (Darwin)
> Comment: Using GnuPG with Mozilla -http://enigmail.mozdev.org/
>
> iQGUBAEBAgAGBQJOrC/4AAoJEADcfz7u4AZjs6oLvi3+vE47pMiKYgxhe06ys8/6
> g+QaqmQLSzMB+Vs200YCCce5tbMJmCw93f6dBOw6QYzHvzTegF1n3UO9ThFdMgmY
> 0ncZTdgedhZcPix7D8rgTLRO4out/8vXECSgHRxm+ZW5w+dm86fF6CnXXwaBjB+n
> jU2kHA3SA4kmTfY9MhosRF9R+yXlyfmEBc3qfQ7nmSjgtQ6/X4elk+fmi9sXRb73
> JwGYWGJ3r2Van4iRCI0PRfsDJj6B2MSI3ZbS1NSTpLzLmTkExvRiRtxQKo8oDPs3
> e6nP1hgcZptvd/LKwNnl3JPPWvqpVhbY8TUPhlTW5oVuTiX4uzPdMYK5uNJMG31T
> sj8wdb13HvP7ynmjpDKnG7oxN3j6y+6h/5U5BEP4Ok6XX+Ik14fRSMMBLQUstHDT
> 6THN5rE/QQZ2ofYleUAM/jBQqTGT1USa7cQ7gCPHv6olNsgXdHiVydhhsDXXTkTL
> 8VdvsJjsP5KYEbc7rTMJqxrdvd/wSrs=
> =78F1
> -----END PGP SIGNATURE-----
>
>  lists.vcf
> < 1KViewDownload

mguserdev

unread,
Oct 29, 2011, 1:13:06 PM10/29/11
to mongodb-user
One thing I wanted to point out is that I need the name:'ccc' in the
query criteria (since removing it and making the query criteria solely
'_id:345' does work), since each counter doc in the collection is
described by various attributes (the 'name' field is a simplification
here), and in the actual collection, the name field has a unique index
covering 3+ different fields.
Reply all
Reply to author
Forward
0 new messages