サブテーブル内の住所でジオコーディング・緯度経度取得

お世話になります。
サブテーブル内の住所でジオコーディングを行い、同じくサブテーブル内の緯度・経度フィールドに取得した緯度・経度を格納したいのですが、格納しようとするともともと入っていたテーブル内のデータがすべて消えたりしてしまいます。
現状のコードは以下のものですが、正常に動きません。
ご教授お願いいたします。
function setTableDetail(event) {
var v;
// レコード情報を取得します
var recs = event[‘record’];
var table = recs.土地情報.value;
for( i=0;i<table.length;i++){
// Google Geocoder を定義します
var gc = new google.maps.Geocoder();

// 住所が入力されていなければ、ここで処理を終了します
    if (table[i].value['住所'].value === undefined){return;}
    if (table[i].value['住所'].value.length === 0){return;}

    // 緯度・経度が入力されていなければ、住所から緯度・経度を算出します 
    if (table[i].value['lat1'].value === undefined || 
        table[i].value['lng1'].value === undefined || 
        table[i].value['lat1'].value.length === 0 || 
        table[i].value['lng1'].value.length === 0){
        // Geocoding API を実行します
        gc.geocode({
            address: table[i].value['住所'].value,
            language: 'ja',
            country: 'JP'
        }, function(results, status) {  
            // 住所が検索できた場合、開いているレコードに対して
            // 緯度・経度を埋め込んで更新します
            //更新オブジェクト
    var putObj= {
    "app": kintone.app.getId(),
    "id": kintone.app.record.getId(),
    "record": {
    "土地情報": {
    "value": [
    {"id": fa,
    "value":{
    "lat1":
        {"value":results[0].geometry.location.lat()}}},
    {"id": fa, 
    "value":
        {"lng1":{"value":results[0].geometry.location.lng()}}}
    ]
    }
    }
    }
    kintone.api('/k/v1/records', 'PUT', putObj);

           });
        }
}//for
    }

また、このコードは
https://cybozudev.zendesk.com/hc/ja/articles/202341964-%E9%A1%A7%E5%AE%A2%E8%A8%AA%E5%95%8F%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%9C%B0%E5%9B%B3%E3%81%AB%E3%83%94%E3%83%B3%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B

こちらの詳細画面参照時に呼び出し、動かしたいと考えております。
よろしくお願いいたします。

あれ さん
cstapの瀧ヶ平です。

テーブルフィールドの更新をREST APIで行うにはこちらにあるように

"レコードのフィールドコード": {
  "value": {
    "インデックス値" : {
      // テーブル内のフィールド変更値などの記述
    } 
  }
}

のように記述する必要があります。

なので

function setTableDetail(event) {
    var v;
    // レコード情報を取得します
    var recs = event['record'];
    var table = recs.土地情報.value;
    for( i=0;i<table.length;i++){
        // Google Geocoder を定義します
        var gc = new google.maps.Geocoder();

        // 住所が入力されていなければ、ここで処理を終了します
        if (table[i].value['住所'].value === undefined){return;}
        if (table[i].value['住所'].value.length === 0){return;}

        // 緯度・経度が入力されていなければ、住所から緯度・経度を算出します 
        if (table[i].value['lat1'].value === undefined || 
            table[i].value['lng1'].value === undefined || 
            table[i].value['lat1'].value.length === 0 || 
            table[i].value['lng1'].value.length === 0){
            // Geocoding API を実行します
            gc.geocode({
                address: table[i].value['住所'].value,
                language: 'ja',
                country: 'JP'
            }, (function(results, status) {  
                // 住所が検索できた場合、開いているレコードに対して
                // 緯度・経度を埋め込んで更新します
                //更新オブジェクト
                var putObj= {
                    "app": kintone.app.getId(),
                    "id": kintone.app.record.getId(),
                    "record": {
                        "土地情報": {
                            "value": {
                            }
                        }
                    }
                };
                putObj.record["土地情報"].value[this.id] = 
                                 {
                                     "value":{
                                         "lat1":{
                                            "value":results[0].geometry.location.lat()
                                         },
                                         "lng1":{
                                             "value":results[0].geometry.location.lng()
                                         }
                                     }
                                 };

                kintone.api('/k/v1/records', 'PUT', putObj);

            }).bind({id: i}) // コールバックは非同期なため、bind()によって関数内のthisにidパラメータとしてインデックス値をバインド
            );

        }
    }//for
}

のように修正すれば良いかと思います。

cstap 瀧ヶ平 様
前回に引き続き回答ありがとうございます!

申し訳ございません、
おっしゃられた通りに記述してみたのですが、PUT https://xxxxxxx.cybozu.com/k/v1/records.json 400 (Bad Request)
とエラーになってしまいました。
自分で記述している際にもこのようなエラーを度々見ていたのですが、原因を教えて頂ければ幸いです。
何度も申し訳ございません、よろしくお願いいたします。

あれ さん

おそらく

kintone.api.url("/k/v1/records")

に対してリクエストを送信してるからじゃないでしょうか、レコードの一件更新の場合は

kintone.api.url("/k/v1/record")

が正しいので修正して試してみてください!

すいません、そもそものkintone.apiの第一引数が"/k/v1/records"になってますね。
こちらを

kintone.api.url("/k/v1/record")

に修正すると良いと思います

cstap 瀧ヶ平 様

何度も申し訳ございません…
kintone.api(‘/k/v1/record’, ‘PUT’, putObj);
だと、緯度・経度は入るがテーブルにもともと入っていたデータが消える

kintone.api.url(‘/k/v1/record’, ‘PUT’, putObj);
だと、何も起こらない
データはなぜ消えてしまうのでしょうか…

すいません書き方が悪かったです、kintone.apiの第一引数を修正するというのは

kintone.api(kintone.api.url("/k/v1/record"), "PUT", putObj);

に修正ですね。

データが消えてしまうのは先ほどのレコードの更新APIのページの注意事項にあるように、テーブルのデータを含む場合リクエストに記述していないデータは削除されてしまうようです。
なので、更新するputObj内にもともとのフィールドの値を格納しておく必要があるようです。
以下のように修正すれば問題ないかと思います。

function setTableDetail(event) {
    var v;
    // レコード情報を取得します
    var recs = event['record'];
    var table = recs.土地情報.value;
    for( i=0;i<table.length;i++){
        // Google Geocoder を定義します
        var gc = new google.maps.Geocoder();

        // 住所が入力されていなければ、ここで処理を終了します
        if (table[i].value['住所'].value === undefined){return;}
        if (table[i].value['住所'].value.length === 0){return;}

        // 緯度・経度が入力されていなければ、住所から緯度・経度を算出します 
        if (table[i].value['lat1'].value === undefined || 
            table[i].value['lng1'].value === undefined || 
            table[i].value['lat1'].value.length === 0 || 
            table[i].value['lng1'].value.length === 0){
            // Geocoding API を実行します
            gc.geocode({
                address: table[i].value['住所'].value,
                language: 'ja',
                country: 'JP'
            }, (function(results, status) {  
                // 住所が検索できた場合、開いているレコードに対して
                // 緯度・経度を埋め込んで更新します
                //更新オブジェクト
                var putObj= {
                    "app": kintone.app.getId(),
                    "id": kintone.app.record.getId(),
                    "record": {
                        "土地情報": {
                            "value": {
                            }
                        }
                    }
                };
                putObj.record["土地情報"].value[this.id] = 
                                 {
                                     "value":{
                                         "lat1":{
                                            "value":results[0].geometry.location.lat()
                                         },
                                         "lng1":{
                                             "value":results[0].geometry.location.lng()
                                         },
                                         "住所": this.address
                                     }
                                 };

                kintone.api(kintone.api.url('/k/v1/record'), 'PUT', putObj);

            }).bind({id: i, address: table[i].value['住所']})
            );

        }
    }//for
}

cstap 瀧ヶ平 様

ありがとうございます。
説明を理解できず、申し訳ございませんでした。

頂いたコードなのですが、テーブルの値が複数行あった際に
最終行だけ残る形(一行のみ)となってしまいます。
更新をする際、行のIDが0に戻ってしまっているのでしょうか?

よろしくお願いいたします。

あれ さん

すいません、テーブルの更新は各行のデータを毎回代入しないとほかの行のデータも消えてしまうようですね。
putObjをループの外で宣言し、テーブルのデータをループの中で追加していき、テーブルのデータの数がもともとのテーブルと一致したときに更新する。
というようなやり方であればよさそうです。

具体的には以下のようなものになります。

function setTableDetail(event) {
    var v;
    // レコード情報を取得します
    var recs = event['record'];
    var table = recs.土地情報.value;
    var putObj= {
        "app": kintone.app.getId(),
        "id": kintone.app.record.getId(),
        "record": {
            "土地情報": {
                "value": {
                }
            }
        }
    };
    for( i=0;i<table.length;i++){
        // Google Geocoder を定義します
        var gc = new google.maps.Geocoder();

        // 住所が入力されていなければ、ここで処理を終了します
        if (table[i].value['住所'].value === undefined){return;}
        if (table[i].value['住所'].value.length === 0){return;}

        // 緯度・経度が入力されていなければ、住所から緯度・経度を算出します 
        if (table[i].value['lat1'].value === undefined || 
            table[i].value['lng1'].value === undefined || 
            table[i].value['lat1'].value.length === 0 || 
            table[i].value['lng1'].value.length === 0){
            // Geocoding API を実行します
            gc.geocode({
                address: table[i].value['住所'].value,
                language: 'ja',
                country: 'JP'
            }, (function(results, status) {  
                // 住所が検索できた場合、開いているレコードに対して
                // 緯度・経度を埋め込んで更新します
                //更新オブジェクト
                putObj.record["土地情報"].value[this.id] = 
                                 {
                                     "value":{
                                         "lat1":{
                                            "value":results[0].geometry.location.lat()
                                         },
                                         "lng1":{
                                             "value":results[0].geometry.location.lng()
                                         },
                                         "住所": this.address
                                     }
                                 };

                if(Object.keys(putObj.record["土地情報"].value).length === table.length) kintone.api(kintone.api.url('/k/v1/record'), 'PUT', putObj);

            }).bind({id: i, address: table[i].value['住所']})
            );

        }
    }//for
}

cstap 瀧ヶ平 様
ありがとうございます!動きました!
完全に行き詰っていたので、本当に助かりました。
何度もご丁寧な回答、本当にありがとうございました!

cstap 瀧ヶ平 様
お世話になります。
昨日はありがとうございました。

申し訳ございません、再び質問したい箇所が出てきたので、こちらにて質問させていただきます。
昨日取得した緯度・経度をもとに一覧画面の地図にピン表示を行いました。
さらに、ピンをクリックした際に吹き出しを表示し、吹き出しにはそれぞれの住所を表示させたいと考えております。
現状では、すべてのピンで一番最後の住所が表示されている状態です。
度々申し訳ございません、なにとぞよろしくお願いいたします。

var table = rec[i].土地情報.value;
for (s = 0;s<table.length;s++){
ido = table[s].value[‘lat1’].value;
keido = table[s].value[‘lng1’].value;
add = table[s].value[‘land_address’].value;
p_latlng[s] = new google.maps.LatLng(ido,keido);
pointer = new google.maps.Marker({
position: p_latlng[s],
map: map,
icon: ‘https://chart.googleapis.com/chart?chst=d_bubble_text_small&chld=edge_bc|’ + recno[i] + ‘|FFFFFF|000000’
});
//円を消す
google.maps.event.addListener(pointer, ‘click’, function(event){

circle.setMap(null);
    });
    //吹き出し

    google.maps.event.addListener(pointer, 'click', (function(pointer, s) {
    return function() {
            info.setContent('<a href="https://www.google.co.jp/maps/place/'+add+'" target="_blank" title="詳細地図">'+add+'</a>');
            info.open( map, pointer);
    }
    })( pointer, s));

上のソースを
https://cybozudev.zendesk.com/hc/ja/articles/202341964-%E9%A1%A7%E5%AE%A2%E8%A8%AA%E5%95%8F%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%9C%B0%E5%9B%B3%E3%81%AB%E3%83%94%E3%83%B3%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B
こちらのピン表示部分の中に入れている状態です。
よろしくお願いいたします。

あれ さん

おそらく、ループの最中に設定されるコールバック関数の実行までの間にfor文のループが進んでいるためにコールバック関数内部で参照しているadd や pointerなどの変数に次以降の値が代入されていることによっておっしゃるような現象が起こっているものだと考えられます。
なので、前回修正したコードと同じように無名関数にbindメソッドを用いて正しい値を入れたオブジェクトを用意し関数内のthisにバインドするなどして目的の値を利用できるようにする必要があります。
おそらく以下のコードで対応できるかと思います。

var table = rec[i].土地情報.value;
for (s = 0;s<table.length;s++){
    ido = table[s].value['lat1'].value;
    keido = table[s].value['lng1'].value;
    add = table[s].value['landaddress'].value;
    platlng[s] = new google.maps.LatLng(ido,keido);
    pointer = new google.maps.Marker({
        position: platlng[s],
        map: map,
        icon: 'https://chart.googleapis.com/chart?chst=dbubbletextsmall&chld=edge_bc|' + recno[i] + '|FFFFFF|000000'
    });
    //円を消す
    google.maps.event.addListener(pointer, 'click', function(event){

        circle.setMap(null);
    });
    //吹き出し

    google.maps.event.addListener(pointer, 'click', (function(pointer, s) {
        return function() {
            info.setContent('<a href="https://www.google.co.jp/maps/place/'+this.add+'" target="_blank" title="詳細地図">'+this.add+'</a>');
            info.open( map, this.pointer);
        }
    }).bind({add: add, pointer: pointer})( pointer, s));
}

cstap 瀧ヶ平 様
連絡が遅くなり申し訳ございません。
無事に実装できました!
ありがとうございました。

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。