how to update mongodb with two field - mongodb

db.auto_complete.find()
{ "_id" : ObjectId("6239a3c93a8e84c1b46d1bf4"), "category" : "음식", "keyword" : "삼겹살", "weight" : 0, "shard" : 5, "searchCount" : 3, "satisfactionCount" : 4, "force" : false }
but i want to update weight = (searchCount X 0.5 + satisfactionCount X 0.5)
my wanted result =
{ "_id" : ObjectId("6239a3c93a8e84c1b46d1bf4"), "category" : "음식", "keyword" : "삼겹살", "weight" : 3, "shard" : 5, "searchCount" : 3, "satisfactionCount" : 4, "force" : false }
weight = ( 3(searchCount)X0.5 + 4(satisfactionCount)X0.5 ) =>3.5 (+round off) => 3
i have tried with $set but i didn't solved this problem how to query this problem with mongo
and if weight have decimal point i want round off the decimal point
please help me....

Maybe something like this:
db.collection.update({},
[
{
$addFields: {
// weight = (searchCount X 0.5 + satisfactionCount X 0.5)
weight: {
$trunc: [
{
"$sum": [
{
"$multiply": [
"$searchCount",
0.5
]
},
{
"$multiply": [
"$satisfactionCount",
0.5
]
}
]
},
0
]
}
}
}
],{multi:true})
Explained:
Use the the update with aggregation pipeline method ( mongodb 4.2+ ) to replace the weight value with the rounded calculated based on provided formula. Add the option { multi:true } to apply to all documents in the collection.
playground

Related

In MongoDB, how do I increase multiple values?

The database document looks like :
{ "_id" : 12345,
"options" : [
{
"no" : 1,
"apples" : 0
},
{
"no" : 2,
"apples" : 0
},
{
"no" : 3,
"apples" : 0
}
]
}
and I want(with one query) to increment apples on only say numbers 1 and 3, each by one. Thanks.
You can use the arrayFilters for updating the fields in an array:
here is the query I wrote to update the values:
db.sample.update(
{},
{
$inc:{
"options.$[options].apples":1
}
},
{
arrayFilters:[
{
"options.no":{
$in:[1,3]
}
}
]
}
)
You can set your filters in arrayFilters according to your requirements.
For more about arrayFilters read here.
Hope this will help :)

Insert new fields to document at given array index in MongoDB

I have the following document structure in a MongoDB collection :
{
"A" : [ {
"B" : [ { ... } ]
} ]
}
I'd like to update this to :
{
"A" : [ {
"B" : [ { ... } ],
"x" : [],
"y" : { ... }
} ]
}
In other words, I want the "x" and "y" fields to be added to the first element of the "A" array without loosing "B".
Ok as there is only one object in A array you could simply do as below :
Sample Collection Data :
{
"_id" : ObjectId("5e7c3cadc16b5679b4aeec26"),
A:[
{
B: [{ abc: 1 }]
}
]
}
Query :
/** Insert new fields into 'A' array's first object by index 0 */
db.collection.updateOne(
{ "_id" : ObjectId("5e7c3f77c16b5679b4af4caf") },
{ $set: { "A.0.x": [] , "A.0.y" : {abcInY :1 }} }
)
Output :
{
"_id" : ObjectId("5e7c3cadc16b5679b4aeec26"),
"A" : [
{
"B" : [
{
"abc" : 1
}
],
"x" : [],
"y" : {
"abcInY" : 1.0
}
}
]
}
Or Using positional operator $ :
db.collection.updateOne(
{ _id: ObjectId("5e7c3cadc16b5679b4aeec26") , 'A': {$exists : true}},
{ $set: { "A.$.x": [] , "A.$.y" : {abcInY :1 }} }
)
Note : Result will be the same, but functionally when positional operator is used fields x & y are inserted to first object of A array only when A field exists in that documents, if not this positional query would not insert anything (Optionally you can check A is an array condition as well if needed). But when you do updates using index 0 as like in first query if A doesn't exist in document then update would create an A field which is an object & insert fields inside it (Which might cause data inconsistency across docs with two types of A field) - Check below result of 1st query when A doesn't exists.
{
"_id" : ObjectId("5e7c3f77c16b5679b4af4caf"),
"noA" : 1,
"A" : {
"0" : {
"x" : [],
"y" : {
"abcInY" : 1.0
}
}
}
}
However, I think I was able to get anothe#whoami Thanks for the suggestion, I think your first solution should work. However, I think I was able to get another solution to this though I'm not sure if its better or worse (performance wise?) than what you have here. My solution is:
db.coll.update( { "_id" : ObjectId("5e7c4eb3a74cce7fd94a3fe7") }, [ { "$addFields" : { "A" : { "x" : [ 1, 2, 3 ], "y" : { "abc" } } } } ] )
The issue with this is that if "A" has more than one array entry then this will update all elements under "A" which is not something I want. Just out of curiosity is there a way of limiting this solution to only the first entry in "A"?

Does mongodb have a product equivalent of the aggregate $sum

I am trying to calculate cumulative returns for a portfolio of stocks in mongodb and ideally would be able to use a cumulative $product accumulator
e.g. If I have three documents one with the value 0.5, the next 0.6 and the final having 0.7
I can easily calculate the sum using the aggregate accumulator $sum. This will give 0.5+0.6+0.7.
What I would like to do is calculate the cumulative product ($product) of these values i.e. 0.5*0.6*0.5? Can this be done directly of do I have to use logs?
The document structure is something like the following
{
"date" : 2015-12-31T15:50:00.000Z,
"time" : 1550,
"aum" : 1000000,
"basket" :[
{
"_id" : "Microsoft",
"return" : 0.03,
"shares" : 10,
"price" : 56.53,
"fx" : 1.0
},
.
.
.
{
"_id" : "GOOG.N",
"return" : 0.05,
"shares" : 20,
"price" : 759.69,
"fx" : 1.0
}
you can use $multiply (aggregation)
> db.stocks.aggregate( {$project: { total: { $multiply: [ 0.5,0.6,0.5 ] } }} )
UPDATE:
This will calculate product of each stock in a separate document:
> var total=1;db.stocks.find().forEach(function(doc){total=total*doc.stock;})
> total
you need to use $multiply and below is a sample query
db.stocks.aggregate( [{ total: { $multiply: [ "$price", "$quantity" ] } } ])

Force list type in $min update operator

I have documents with the following structure:
{
"_id" : 0,
"mins" : {
"ts1" : {
"node1" : [
1,
2,
3
],
"node2" : [
4,
5,
6
]
}
}
}
I'd like to update documents by taking the component-wise minimum for an array. As MongoDB does not support $min on arrays (I think), I'm updating each index individually like so:
db.foo.updateOne(
{"_id" : 0},
{$min: {
"mins.ts3.node1.0": 1,
"mins.ts3.node1.1": 2
}}
)
This works fine but the problem is that if the document does not have the array before updating, MongoDB creates a nested document instead of an array:
{
"_id" : 0,
"mins" : {
"ts1" : {
"node1" : [
1,
2,
3
],
"node2" : [
4,
5,
6
]
},
"ts3" : {
"node1" : {
"0" : 1,
"1" : 2
}
}
}
}
Is there a way to tell MongoDB it is updating a list even if the list does not exist yet?
I'd like to avoid creating empty lists for each document as that would break my current program design.

Compare array elements,remove the one with the lowest score

There are 200 documents in school db. I must remove each document which has "type":"homework" and the lowest score.
{
"_id" : 0,
"name" : "aimee Zank",
"scores" :
[
{
"type" : "exam",
"score" : 1.463179736705023
},
{
"type" : "quiz",
"score" : 11.78273309957772
},
{
"type" : "homework",
"score" : 6.676176060654615
},
{
"type" : "homework",
"score" : 35.8740349954354
}
]
}
For example,here
{
"type" : "homework",
"score" : 6.676176060654615
}
must be removed as score = 6.6 < 35.8
I sorted all the documents like this:
db.students.find({"scores.type":"homework"}).sort({"scores.score":1})
But I do not know how then to remove the doc having the lowest score and type:homework???
NOTE: how to solve it by not using aggregation method? E.g., by sorting and then updating.
This can be done in a couple of steps. The first step is to grab a list of the documents with the minimum score by using the aggregation framework with $match, $unwind and $group operators that streamlines your documents to find the minimum score for each document:
lowest_scores_docs = db.school.aggregate([
{ "$match": {"scores.type": "homework"} },
{ "$unwind": "$scores" }, { "$match": {"scores.type": "homework"} },
{ "$group": { "_id":"$_id", "lowest_score": {"$min": "$scores.score" } } } ] )
The second step is to loop through the dictionary above and use the $pull operator in the update query to remove the element from the array as follows:
for result in lowest_scores_docs["result"]:
db.school.update({ "_id": result["_id"] },
{ "$pull": { "scores": { "score": result["lowest_score"] } } } )
import pymongo
import sys
# connnecto to the db on standard port
connection = pymongo.MongoClient("mongodb://localhost")
db = connection.school # attach to db
students = db.students # specify the colllection
try:
cursor = students.find({})
print(type(cursor))
for doc in cursor:
hw_scores = []
for item in doc["scores"]:
if item["type"] == "homework":
hw_scores.append(item["score"])
hw_scores.sort()
hw_min = hw_scores[0]
#students.update({"_id": doc["_id"]},
# {"$pull":{"scores":{"score":hw_min}}})
except:
print ("Error trying to read collection:" + sys.exc_info()[0])